Java Tread多线程(2)多线程安全问题
2016-01-09 16:46
387 查看
作者 :卿笃军
原文地址:/article/2629630.html
本文演示,Tread多线程安全问题,以及几种解决多线程安全方式(线程同步)。
1)一个线程不安全的Demo
2)线程同步(synchronized,函数同步,this锁,Class对象锁)
一、小Demo演示引出线程安全问题:
执行显示结果:
以上打印出了0,-1,-2等数字。发现没?(线程出问题了吧!
!!
)
问题:出问题的解决办法是什么呢?
解释:线程1进入,强制睡眠10ms。此时线程2进入,又强制睡眠10ms;线程3进入又强制睡眠10ms。线程4进入再强制睡眠10ms;
注意,以上4个线程睡眠时都已经进入了if语句,进入的时候x>0还是成立的;
好了。线程1醒来,開始打印打印5,4,3,2,这时候--x还没运行。线程2就醒来了。抢去了cpu的运行权.....................
二、线程同步
问题:对于上面的问题,我们是不是能够採取一个这种措施?当线程1运行run代码段的时候。我们不让其它的线程来运行,直到线程1运行完,其它的线程才干够进入。
解决方式:好在Java里面本来就有这种函数。将代码段包裹起来。就能够达到上面问题描写叙述的效果。
函数名:synchronized,须要一个參数。随便传个对象就ok了(详细參数差别分析。请往下拉见附录1)。
1)一个简单的解决方式:
2)换一种更简单的解决方法:函数同步(将synchronized直接加入在函数前面)
说明:有没有发现,函数就是对多个语句的打包?可是,函数仅仅是打包。而没有像上面的synchronized一样实现同步。可是有一种方法能够达到这个效果。看以下的小Demo就明确了。
附录1:对于函数锁中synchronized中的參数的解释分析(我们先看一下以下这个小Demo)
郁闷吧,又出现线程安全问题了,但是我们分明都加了锁的呀?这是什么原因导致的呢?事实上,问题就出在了。synchronized里面的參数上。
函数同步锁定的是this,而上面的小Demo里面,一个是函数同步锁(this),另外一个是obj锁,发现没?解决方式:将obj锁改为this锁就没问题了。
解决后的小Demo:
附录2:提出另外一个问题,既然函数同步锁定的是this,那么例如以下的这个函数要怎样解释?静态函数没有this,怎样锁定?
事实上这里static函数的锁是Class对象。以下注意看例如以下小Demo中synchronized的參数。
解决后的小Demo:
执行显示结果:(同上)
參考文献:Java视频 毕向东 主讲
原文地址:/article/2629630.html
原文地址:/article/2629630.html
本文演示,Tread多线程安全问题,以及几种解决多线程安全方式(线程同步)。
1)一个线程不安全的Demo
2)线程同步(synchronized,函数同步,this锁,Class对象锁)
一、小Demo演示引出线程安全问题:
package thread.runable1.qdj; //1.定义类实现Runnable接口 class RunDemo1 implements Runnable { private int x = 5; //2.覆盖Runnable接口中的run方法 //将线程代码存放在run中 public void run() { while (true) { if (x > 0) { //加入sleep(),注意:sleep()会抛出异常 try { Thread.sleep(10); //让线程睡眠10ms } catch (Exception e) { e.printStackTrace(); } System.out.println("Runnable:"+x); --x; } } } } public class CRunableDemo1 { public static void main(String[] args) { RunDemo1 r = new RunDemo1(); //3.通过Thread类建立线程对象,并将Runnable接口的子类对象作为參数 Thread t1 = new Thread(r); Thread t2 = new Thread(r); Thread t3 = new Thread(r); Thread t4 = new Thread(r); //4.使用start开启线程 t1.start(); t2.start(); t3.start(); t4.start(); } }
执行显示结果:
以上打印出了0,-1,-2等数字。发现没?(线程出问题了吧!
!!
)
问题:出问题的解决办法是什么呢?
解释:线程1进入,强制睡眠10ms。此时线程2进入,又强制睡眠10ms;线程3进入又强制睡眠10ms。线程4进入再强制睡眠10ms;
注意,以上4个线程睡眠时都已经进入了if语句,进入的时候x>0还是成立的;
好了。线程1醒来,開始打印打印5,4,3,2,这时候--x还没运行。线程2就醒来了。抢去了cpu的运行权.....................
二、线程同步
问题:对于上面的问题,我们是不是能够採取一个这种措施?当线程1运行run代码段的时候。我们不让其它的线程来运行,直到线程1运行完,其它的线程才干够进入。
解决方式:好在Java里面本来就有这种函数。将代码段包裹起来。就能够达到上面问题描写叙述的效果。
函数名:synchronized,须要一个參数。随便传个对象就ok了(详细參数差别分析。请往下拉见附录1)。
1)一个简单的解决方式:
package thread.runable1.qdj; //1.定义类实现Runnable接口 class RunDemo1 implements Runnable { private int x = 5; Object obj = new Object(); //2.覆盖Runnable接口中的run方法 //将线程代码存放在run中 public void run() { while (true) { synchronized (obj) { if (x > 0) { //加入sleep()。注意:sleep()会抛出异常 try { Thread.sleep(10); //让线程睡眠10ms } catch (Exception e) { e.printStackTrace(); } System.out.println("Runnable:"+x); --x; } } } } } public class CRunableDemo1 { public static void main(String[] args) { RunDemo1 r = new RunDemo1(); //3.通过Thread类建立线程对象,并将Runnable接口的子类对象作为參数 Thread t1 = new Thread(r); Thread t2 = new Thread(r); Thread t3 = new Thread(r); Thread t4 = new Thread(r); //4.使用start开启线程 t1.start(); t2.start(); t3.start(); t4.start(); } }执行结果显示:
2)换一种更简单的解决方法:函数同步(将synchronized直接加入在函数前面)
说明:有没有发现,函数就是对多个语句的打包?可是,函数仅仅是打包。而没有像上面的synchronized一样实现同步。可是有一种方法能够达到这个效果。看以下的小Demo就明确了。
package thread.runable1.qdj; //同步函数 class SynFunc { private int x = 5; public synchronized void aFunc() { while (true) { if (x > 0) { //加入sleep(),注意:sleep()会抛出异常 try { Thread.sleep(10); //让线程睡眠10ms } catch (Exception e) { e.printStackTrace(); } System.out.println("Runnable:"+x); --x; } } } } //1.定义类实现Runnable接口 class RunDemo1 implements Runnable { private SynFunc syn = new SynFunc(); //2.覆盖Runnable接口中的run方法 //将线程代码存放在run中 public void run() { syn.aFunc(); } } public class CRunableDemo1 { public static void main(String[] args) { RunDemo1 r = new RunDemo1(); //3.通过Thread类建立线程对象,并将Runnable接口的子类对象作为參数 Thread t1 = new Thread(r); Thread t2 = new Thread(r); Thread t3 = new Thread(r); Thread t4 = new Thread(r); //4.使用start开启线程 t1.start(); t2.start(); t3.start(); t4.start(); } }执行结果显示:(同上)
附录1:对于函数锁中synchronized中的參数的解释分析(我们先看一下以下这个小Demo)
package thread.runable1.qdj; //1.定义类实现Runnable接口 class RunDemo1 implements Runnable { private int x = 100; Object obj = new Object(); boolean flag = true; //2.覆盖Runnable接口中的run方法 //将线程代码存放在run中 public void run() { if (flag) { while (true) { synchronized(obj) { if (x > 0) { //加入sleep(),注意:sleep()会抛出异常 try { Thread.sleep(10); //让线程睡眠10ms } catch (Exception e) { e.printStackTrace(); } System.out.println("Runnable:"+x); --x; } } } } else { while (true) aFunc(); } } public synchronized void aFunc() { while (true) { if (x > 0) { //加入sleep(),注意:sleep()会抛出异常 try { Thread.sleep(10); //让线程睡眠10ms } catch (Exception e) { e.printStackTrace(); } System.out.println("Runnable:"+x); --x; } } } } public class CRunableDemo1 { public static void main(String[] args) { RunDemo1 r = new RunDemo1(); //3.通过Thread类建立线程对象。并将Runnable接口的子类对象作为參数 Thread t1 = new Thread(r); Thread t2 = new Thread(r); //4.使用start开启线程 t1.start(); //加入sleep()。注意:sleep()会抛出异常 try { Thread.sleep(10); //让线程睡眠10ms } catch (Exception e) { e.printStackTrace(); } r.flag = false; t2.start(); } }执行显示结果:
郁闷吧,又出现线程安全问题了,但是我们分明都加了锁的呀?这是什么原因导致的呢?事实上,问题就出在了。synchronized里面的參数上。
函数同步锁定的是this,而上面的小Demo里面,一个是函数同步锁(this),另外一个是obj锁,发现没?解决方式:将obj锁改为this锁就没问题了。
解决后的小Demo:
package thread.runable1.qdj; //1.定义类实现Runnable接口 class RunDemo1 implements Runnable { private int x = 100; Object obj = new Object(); boolean flag = true; //2.覆盖Runnable接口中的run方法 //将线程代码存放在run中 public void run() { if (flag) { while (true) { synchronized(this) { if (x > 0) { //加入sleep(),注意:sleep()会抛出异常 try { Thread.sleep(10); //让线程睡眠10ms } catch (Exception e) { e.printStackTrace(); } System.out.println("Runnable:"+x); --x; } } } } else { while (true) aFunc(); } } public synchronized void aFunc() { while (true) { if (x > 0) { //加入sleep(),注意:sleep()会抛出异常 try { Thread.sleep(10); //让线程睡眠10ms } catch (Exception e) { e.printStackTrace(); } System.out.println("Runnable:"+x); --x; } } } } public class CRunableDemo1 { public static void main(String[] args) { RunDemo1 r = new RunDemo1(); //3.通过Thread类建立线程对象,并将Runnable接口的子类对象作为參数 Thread t1 = new Thread(r); Thread t2 = new Thread(r); //4.使用start开启线程 t1.start(); //加入sleep()。注意:sleep()会抛出异常 try { Thread.sleep(10); //让线程睡眠10ms } catch (Exception e) { e.printStackTrace(); } r.flag = false; t2.start(); } }执行显示结果:
附录2:提出另外一个问题,既然函数同步锁定的是this,那么例如以下的这个函数要怎样解释?静态函数没有this,怎样锁定?
public static synchronized void aFunc() { while (true) { if (x > 0) { //加入sleep(),注意:sleep()会抛出异常 try { Thread.sleep(10); //让线程睡眠10ms } catch (Exception e) { e.printStackTrace(); } System.out.println("Runnable:"+x); --x; } } }解决方式:静态函数,是类函数由类调用。
事实上这里static函数的锁是Class对象。以下注意看例如以下小Demo中synchronized的參数。
解决后的小Demo:
package thread.runable1.qdj;
//1.定义类实现Runnable接口
class RunDemo1 implements Runnable
{
private static int x = 100;
boolean flag = true;
//2.覆盖Runnable接口中的run方法
//将线程代码存放在run中
public void run()
{
if (flag)
{
while (true)
{
synchronized(RunDemo1.class)
{
if (x > 0)
{
//加入sleep(),注意:sleep()会抛出异常
try {
Thread.sleep(10); //让线程睡眠10ms
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Runnable:"+x);
--x;
}
}
}
}
else
{
while (true)
aFunc();
}
}
public static synchronized void aFunc() { while (true) { if (x > 0) { //加入sleep(),注意:sleep()会抛出异常 try { Thread.sleep(10); //让线程睡眠10ms } catch (Exception e) { e.printStackTrace(); } System.out.println("Runnable:"+x); --x; } } }
}
public class CRunableDemo1 {
public static void main(String[] args) {
RunDemo1 r = new RunDemo1();
//3.通过Thread类建立线程对象。并将Runnable接口的子类对象作为參数
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
//4.使用start开启线程
t1.start();
//加入sleep(),注意:sleep()会抛出异常
try {
Thread.sleep(10); //让线程睡眠10ms
} catch (Exception e) {
e.printStackTrace();
}
r.flag = false;
t2.start();
}
}
执行显示结果:(同上)
參考文献:Java视频 毕向东 主讲
原文地址:/article/2629630.html
相关文章推荐
- trove4j高性能Java集合库
- java之内存可见型
- Java关键字final、static使用总结
- 创建SpringMVC前端配置文件DispatcherServlet总是ClassNotFoundException
- Java中String的探究
- java泛型,枚举的意义
- MyEclipse 中没有 add hibernate capabilities 的解决方法
- Java 统计字符串里英文字母、空格、数字和其它字符的个数
- java 文件上传支持断点续传
- Java相对路径读取文件
- Struts2 过滤器实现只允许POST请求
- Java_基本数据类型
- 利用javap -verbose 查看java程序运行内存分配情况
- Spring AOP面向切面编程
- spring事物属性与隔离级别
- Java就业指导
- 深入分析JavaWeb Item46 -- Struts2数据校验与国际化
- ueditor整合struts2图片无法上传问题
- springmvc之redirect重定向
- SpringMVC框架中多数据源的配置问题、datasource