线程:进程(process)就是一块包含了某些资源的内存区域。操作系统利用进程把它的工作划分为一些功能单元。

线程:进程中所包含的一个或多个执行单元称为线程(thread)。进程还拥有一个私有的虚拟地址空间,该空间仅能被它所包含的线程访问。

线程和进程的区别如下:

1)一个进程至少有一个线程。线程的划分尺度小于进程,使得多线程程序的并发性高。另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。

2)线程在执行过程中与进程的区别在于每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。

3)从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用来实现进程的调度和管理以及资源分配。

2 简述线程的状态及其转换

1)New,创建一个线程,但是线程并没有进行任何的操作。

2)Runnable,新线程从New状态,调用start方法转换到Runnable状态。线程调用start方法向线程调度程序(JVM或者是操作系统)注册一个线程,这个时候一切就绪只等CPU的时间。

3)Running,从Runnable状态到Running状态,线程调度根据调度策略的不同调度不同的线程,被调度执行的线程进入Running状态,执行run方法。

4)Dead状态,从Running状态到Runnable,run方法运行完毕后,线程就会被抛弃,线程就进入Dead状态。

5)Block状态,从Running状态到Block状态,如果线程在运行的状态中因为I/O阻塞、调用了线程的sleep方法以及调用对象的wait方法则线程将进入阻塞状态,直到这些阻塞原因被结束,线程进入到Runnable状态。

3 简述线程的两种创建方式以及它们的区别

创建线程的两种方式:

1)使用Thread创建线程。Thread类是线程类,其每一个实例表示一个可以并发运行的线程。我们可以通过继承该类并重写run方法来定义一个具体的线程。其中重写run方法的目的是定义该线程要执行的逻辑。启动线程时调用线程的start()方法而非直接调用run()方法。start()方法会将当前线程纳入线程调度,使当前线程可以开始并发运行。当线程获取时间片段后会自动开始执行run方法中的逻辑。

2)使用Runnable创建线程。实现Runnable接口并重写run方法来定义线程体,然后在创建线程的时候将Runnable的实例传入并启动线程。

两种创建线程方式的区别:

使用Thread创建线程,编写简单,可以直接操纵线程,无需使用Thread.currentThread(),但是不能够再继承其他类。

使用Runnable创建线程可以将线程与线程要执行的任务分离开减少耦合,同时Java是单继承的,定义一个类实现Runnable接口,这样该类还可以继承自其他类。

多线程实现方法

使用Thread创建线并启动线程

java.lang.Thread类是线程类,其每一个实例表示一个可以并发运行的线程。我们可以通过继承该类并重写run方法来定义一个具体的线程。其中

重写run方法的目的是定义该线程要执行的逻辑。启动线程时调用线程的start()方法而非直接调用run()方法。start()方法会将当前线程纳入线程调

度,使当前线程可以开始并发运行。当线程获取时间片段后会自动开始执行run方法中的逻辑。

public class TestThread extends Thread{

@Override

public void run() {

for(int i=0;i<100;i++){

System.out.println("我是线程");

}

}

}

创建预启动线程

Thread thread = new TestThread();//实例化线程

thread.start();//启动线程

使用Runnable创建并启动线程

实现Runnable接口并重写run方法来定义线程体,然后在创建线程的时候将Runnable的实例传入并启动线程。

这样做的好处在于可以将线程与线程要执行的任务分离开减少耦合,同时java是单继承的,定义一个类实现Runnable接口这样的做法可以更好的

去实现其他父类或接口。因为接口是多继承关系。

public class TestRunnable implements Runnable{

@Override

public void run() {

for(int i=0;i<100;i++){

System.out.println("我是线程");

}

}

}

启动线程的方法:

Runnable runnable = new TestRunnable();

Thread thread = new Thread(runnable);//实例化线程并传入线程体

thread.start();//启动线程

使用内部类创建线程

通常我们可以通过匿名内部类的方式创建线程,使用该方式可以简化编写代码的复杂度,当一个线程仅需要一个实例时我们通常使用这种方式来

创建。

例如:

继承Thread方式:

Thread thread = new Thread(){ //匿名类方式创建线程

public void run(){

//线程体

}

};

thread.start();//启动线程

Runnable方式:

Runnable runnable = new Runnable(){ //匿名类方式创建线程

public void run(){

}

};

Thread thread = new Thread(runnable);

thread.start();//启动线程

线程的方法

currentThread:方法可以用于获取运行当前代码片段的线程

Thread current = Thread.currentThread();

获取线程信息

Thread提供了 获取线程信息的相关方法:

long getId():返回该线程的标识符

String getName():返回该线程的名称

int getPriority():返回线程的优先级

Thread.state getState():获取线程的状态

boolean isAlive():测试线程是否处于活动状态

boolean isDaemon():测试线程是否为守护线程

boolean isInterrupted():测试线程是否已经中断

线程优先级

线程的切换是由线程调度控制的,我们无法通过代码来干涉,但是我们可以通过提高线程的优先级来最大程度的改善线程获取时间片的几率。

线程的优先级被划分为10级,值分别为1-10,其中1最低,10最高。线程提供了3个常量来表示最低,最高,以及默认优先级:

Thread.MIN_PRIORITY,

Thread.MAX_PRIORITY,

Thread.NORM_PRIORITY

设置优先级的方法为:

void setPriority(int priority)

守护线程

守护线程与普通线程在表现上没有什么区别,我们只需要通过Thread提供的方法来设定即可:

**void setDaemon(boolean )**

当参数为true时该线程为守护线程。

守护线程的特点是,当进程中只剩下守护线程时,所有守护线程强制终止。

GC就是运行在一个守护线程上的。

需要注意的是,设置线程为后台线程要在该线程启动前设置。

Thread daemonThread = new Thread();

daemonThread.setDaemon(true);

daemonThread.start();

sleep方法

Thread的静态方法sleep用于使当前线程进入阻塞状态:

**static void sleep(long ms)**

该方法会使当前线程进入阻塞状态指定毫秒,当指定毫秒阻塞后,当前线程会重新进入Runnable状态,等待分配时间片。

该方法声明抛出一个InterruptException。所以在使用该方法时需要捕获这个异常

**注:**改程序可能会出现"跳秒"现象,因为阻塞一秒后线程并非是立刻回到running状态,而是出于runnable状态,等待获取时间片。那么这段等待

时间就是"误差"。所以以上程序并非严格意义上的每隔一秒钟执行一次输出。

yield方法:

Thread的静态方法yield:

**static void yield()**

该方法用于使当前线程主动让出当次CPU时间片回到Runnable状态,等待分配时间片。

join方法

**void join()**

该方法用于等待当前线程结束。此方法是一个阻塞方法。

该方法声明抛出InterruptException。

线程同步

synchronized关键字

多个线程并发读写同一个临界资源时候会发生"线程并发安全问题“

常见的临界资源:

多线程共享实例变量

多线程共享静态公共变量

若想解决线程安全问题,需要将异步的操作变为同步操作。

所谓异步操作是指多线程并发的操作,相当于各干各的。

所谓同步操作是指有先后顺序的操作,相当于你干完我再干。

同步代码块(synchronized 关键字 ),同步代码块包含两部分:一个作为锁的对象的引用,一个作为由这个锁保护的代码块

这个比较难理解故写了下面代码帮助理解

/**

* 多线程并发安全问题

* 当多个线程同时操作同一资源时,由于

* 线程切换时机不确定,导致出现逻辑混乱。

* 严重时可能导致系统崩溃。

* @author ylg

*

*/

public class SyncDemo1 {

public static void main(String[] args) {

/*

* 当一个方法中的局部内部类想引用该方法

* 的其他局部变量时,这个变量必须被声明

* 为final的

*/

final Table table = new Table();

Thread t1 = new Thread(){

public void run(){

while(true){

int bean = table.getBean();

Thread.yield();//模拟线程切换

System.out.println(

getName()+":"+bean

);

}

}

};

Thread t2 = new Thread(){

public void run(){

while(true){

int bean = table.getBean();

Thread.yield();//模拟线程切换

System.out.println(

getName()+":"+bean

);

}

}

};

t1.start();

t2.start();

}

}

class Table{

//20个豆子

private int beans = 20;

/**

* 当一个方法被synchronized修饰后,该方法

* 成为"同步方法"。多个线程不能同时进入到

* 方法内部。

* @return

*/

public synchronized int getBean(){

if(beans==0){

throw new RuntimeException("没有豆子了!");

}

Thread.yield();//模拟线程切换

return beans--;

}

}

/**

* 有效的缩小同步范围可以保证在

* 安全的前提下提高了并发的效率

* @author ylg

*

*/

public class SyncDemo2 {

public static void main(String[] args) {

final Shop shop = new Shop();

Thread t1 = new Thread(){

public void run(){

shop.buy();

}

};

Thread t2 = new Thread(){

public void run(){

shop.buy();

}

};

t1.start();

t2.start();

}

}

class Shop{

/*

* 在方法上使用synchroinzed,同步监视器对象即当前方法所属对象:this

*/

//public synchronized void buy(){

public void buy(){

try{

Thread t = Thread.currentThread();

System.out.println(t+"正在挑选衣服..");

Thread.sleep(5000);

/*

* 同步块可以缩小同步范围。

* 但是必须保证"同步监视器"即:"上锁对象"是同一个才可以。

* 通常,在一个方法中使用this所谓同步监视器对象即可。

*/

synchronized (this) {

System.out.println(t+"正在试衣服..");

Thread.sleep(5000);

}

System.out.println(t+"结账离开");

}catch(Exception e){

}

}

}

/**

* synchronized也成为"互斥锁"

* 当synchronzed修饰的是两段代码,但是"锁对象"相同时,这两段代码就是互斥的。

* @author ylg

*

*/

public class SyncDemo4 {

public static void main(String[] args) {

final Boo b = new Boo();

Thread t1 = new Thread(){

public void run(){

b.methodA();

}

};

Thread t2 = new Thread(){

public void run(){

b.methodB();

}

};

t1.start();

t2.start();

}

}

class Boo{

public synchronized void methodA(){

Thread t = Thread.currentThread();

System.out.println(t+"正在调用方法A");

try {

Thread.sleep(5000);

} catch (InterruptedException e) {

}

System.out.println(t+"调用方法A完毕");

}

public synchronized void methodB(){

Thread t = Thread.currentThread();

System.out.println(t+"正在调用方法B");

try {

Thread.sleep(5000);

} catch (InterruptedException e) {

}

System.out.println(t+"调用方法B完毕");

}

}```

**wait和notify**

多线程之间需要协调工作。

例如,浏览器的一个显示图片的 displayThread想要执行显示图片的任务,必须等待下载线程downloadThread将该图片下载完毕。如果图片还

没有下载完,displayThread可以暂停,当downloadThread完成了任务后,再通知displayThread“图片准备完毕,可以显示了”,这时,

displayThread继续执行。

以上逻辑简单的说就是:如果条件不满足,则等待。当条件满足时,等待该条件的线程将被唤醒。在Java中,这个机制的实现依赖于

wait/notify。等待机制与锁机制是密切关联的

java 多线程 关键字_java多线程基础(synchronize关键字)相关推荐

  1. java线程钥匙_Java多线程并发编程/锁的理解

    一.前言 最近项目遇到多线程并发的情景(并发抢单&恢复库存并行),代码在正常情况下运行没有什么问题,在高并发压测下会出现:库存超发/总库存与sku库存对不上等各种问题. 在运用了 限流/加锁等 ...

  2. java 多线程 总结_Java 多线程总结

    昨天熬了个通宵,看了一晚上的视频,把java 的多线程相关技术重新复习了一遍,下面对学习过程中遇到的知识点进行下总结. 首先我们先来了解一下进程.线程.并发执行的概念: 进程是指:一个内存中运行的应用 ...

  3. java线程 教程_Java多线程系列教程

    Java多线程系列教程 多线程是Java中不可避免的一个重要主体.从本章开始,我们将展开对多线程的学习.接下来的内容是对Java多线程内容的讲解,涉及到的内容包括,Object类中的wait(), n ...

  4. java中的me关键字_java中的volatile关键字

    一.详细解释 在java线程并发处理中,有一个关键字volatile的使用目前存在很大的混淆,以为使用这个关键字,在进行多线程并发处理的时候就可以万事大吉. Java语言是支持多线程的,为了解决线程并 ...

  5. java线程池_Java多线程并发:线程基本方法+线程池原理+阻塞队列原理技术分享...

    线程基本方法有哪些? 线程相关的基本方法有 wait,notify,notifyAll,sleep,join,yield 等. 线程等待(wait) 调用该方法的线程进入 WAITING 状态,只有等 ...

  6. java 线程分组_Java多线程可以分组,还能这样玩!

    前面的文章,栈长和大家分享过多线程创建的3种方式<实现 Java 多线程的 3 种方式>. 但如果线程很多的情况下,你知道如何对它们进行分组吗? 和 Dubbo 的服务分组一样,Java ...

  7. java线程入门_java多线程快速入门(一)

    1.什么是进程 比如:QQ.QQ游戏.eclipse都是进程,可以通过任务管理器查看进程 2.进程和线程区别 线程是进程的一部分,一个进程可以包含多个线程,一个线程只能属于一个进程 进程是所有线程的集 ...

  8. java多线程核心技术_Java多线程编程核心技术(笔记)

    方法内部的私有变量,不存在线程安全问题,永远都是线程安全的,这是方法内部的变量是私有的特性造成的. 实例变量非线程安全,多个线程访问同一个对象的实例变量,则有可能出现非线程安全问题. synchron ...

  9. java 多线程列子_java 多线程例子

    编写具有多线程能力的程序经常会用到的方法有: run(), start(), wait(), notify(), notifyAll(), sleep(), yield(), join() 还有一个重 ...

  10. java的多线程机制_Java多线程开发(一)| 基本的线程机制

    0. 前言 Java 为了实现跨平台,在语言层面上实现了多线程.我们只需要熟悉 Java 这一套多线程机制就行了,比 C/C++ 要容易多了. 1. 定义任务 我们编写程序,最终是为了完成特定的任务. ...

最新文章

  1. 转载:浅谈软件测试流程
  2. Android应用程序消息处理机制(Looper、Handler)分析(1)
  3. 如何给VirtualBox虚拟机的ubuntu LVM分区扩容
  4. linux c socket编程详解,Linux c 网络socket编程
  5. 《MySQL——备库多线程复制策略。》
  6. js获取一个月份最大天数和获取月的最后一天
  7. 特斯拉计划在2023年推出2.5万美元电动汽车,或无方向盘
  8. 微信小程序 网学习址
  9. C#面向对象编程的3个支柱
  10. Atitit 爬虫 node版 attilax
  11. java非静态方法调用静态方法_java - 无法对非静态方法进行静态引用
  12. ArcGIS 10研究(二) 之Mobile新特性
  13. 计算机网络谢希仁第八版 课后答案第七版课后答案
  14. linux抓包工具分析工具下载,Linux下抓包工具tcpdump以及分析包的工具wireshark
  15. 吴文俊人工智能科学技术奖十周年颁奖盛典揭晓,100个项目成果摘得中国智能科学技术奖励最高殊荣
  16. 米思齐(Mixly)图形化系列教程(四)-运算符
  17. Ubuntu安装微软雅黑字体
  18. ApacheCN 活动汇总 2019.8.23
  19. Java 每半年就会更新一次新特性,再不掌握就要落伍了:Java16 的新特性
  20. Web攻防之业务安全指南(网盘下载)

热门文章

  1. Java基础学习总结(162)——如何保证线程安全?
  2. 你不知道的《阿里巴巴Java开发手册》背后故事
  3. word图片靠右_如何设置word图片边缘透明
  4. web dialog 内嵌 图片_Unity游戏如何在iOS上调用Facebook原生对话框分享图片
  5. opencv笔记(6):彩色图像直方图
  6. python 把函数作为参数 ---高阶函数
  7. H3C防火墙出厂空配置管理口无法WEB登录
  8. Windows Server 2008关闭internet explorer增强的安全配置
  9. shell 脚本学习及troubleshooting
  10. 使用Acronis Disk Director Suite调整分区大小