自定义线程类中实例变量针对其他线程可以有共享与不共享的区分,这在多线程中的交互是一个技术点。
(1)不共享数据的情况
多个线程实例
1 package com.cky.thread; 2 3 /** 4 * Created by chenkaiyang on 2017/11/27. 5 */ 6 public class MyThreadTwo extends Thread{ 7 8 private int count = 5; 9 public MyThreadTwo (String name) { 10 super(); 11 this.setName(name); 12 } 13 @Override 14 public void run() { 15 super.run(); 16 while(count > 0) { 17 count --; 18 System.out.println("由" +this.currentThread().getName() +"计算,count="+count); 19 } 20 21 } 22 }
1 package com.cky.test; 2 3 import com.cky.thread.MyThreadTwo; 4 5 /** 6 * Created by chenkaiyang on 2017/11/27. 7 */ 8 public class Test2 { 9 public static void main(String[] args) { 10 MyThreadTwo a = new MyThreadTwo("A"); 11 MyThreadTwo b = new MyThreadTwo("B"); 12 MyThreadTwo c = new MyThreadTwo("C"); 13 a.start(); 14 b.start(); 15 c.start(); 16 } 17 }
D:itjdk1.8injava -Didea.launcher.port=7533 "-Didea.launcher.bin.path=D:itideaIntelliJ IDEA 2016.3.3in" -Dfile.encoding=UTF-8 -classpath "D:itjdk1.8jrelibcharsets.jar;D:itjdk1.8jrelibdeploy.jar;D:itjdk1.8jrelibextaccess-bridge-64.jar;D:itjdk1.8jrelibextcldrdata.jar;D:itjdk1.8jrelibextdnsns.jar;D:itjdk1.8jrelibextjaccess.jar;D:itjdk1.8jrelibextjfxrt.jar;D:itjdk1.8jrelibextlocaledata.jar;D:itjdk1.8jrelibext ashorn.jar;D:itjdk1.8jrelibextsunec.jar;D:itjdk1.8jrelibextsunjce_provider.jar;D:itjdk1.8jrelibextsunmscapi.jar;D:itjdk1.8jrelibextsunpkcs11.jar;D:itjdk1.8jrelibextzipfs.jar;D:itjdk1.8jrelibjavaws.jar;D:itjdk1.8jrelibjce.jar;D:itjdk1.8jrelibjfr.jar;D:itjdk1.8jrelibjfxswt.jar;D:itjdk1.8jrelibjsse.jar;D:itjdk1.8jrelibmanagement-agent.jar;D:itjdk1.8jrelibplugin.jar;D:itjdk1.8jrelib esources.jar;D:itjdk1.8jrelib t.jar;F:springboot hreaddemooutproduction hreaddemo;D:itideaIntelliJ IDEA 2016.3.3libidea_rt.jar" com.intellij.rt.execution.application.AppMain com.cky.test.Test2 由B计算,count=4 由C计算,count=4 由A计算,count=4 由C计算,count=3 由B计算,count=3 由C计算,count=2 由A计算,count=3 由C计算,count=1 由B计算,count=2 由C计算,count=0 由A计算,count=2 由B计算,count=1 由B计算,count=0 由A计算,count=1 由A计算,count=0 Process finished with exit code 0
结果分析,这里一共创建了3个线程实例,每个线程都有各自的count变量,各自递减自己的变量,这就说明这个是变量不共享,不存在多个线程共同访问同一个实例的情况。
(2)共享数据的情况
共享数据的情况就是多个线程可以访问同一个变量
1 package com.cky.thread; 2 3 /** 4 * Created by chenkaiyang on 2017/11/27. 5 */ 6 public class MyThreadThird extends Thread{ 7 private int count = 5; 8 @Override 9 public void run() { 10 super.run(); 11 count -- ; 12 System.out.println("由" + this.currentThread().getName()+"计算count="+count); 13 } 14 }
1 package com.cky.test; 2 3 import com.cky.thread.MyThreadThird; 4 5 /** 6 * Created by chenkaiyang on 2017/11/27. 7 */ 8 public class Test3 { 9 public static void main(String[] args) { 10 MyThreadThird mythread = new MyThreadThird(); 11 Thread a = new Thread(mythread, "A"); 12 Thread b = new Thread(mythread, "B"); 13 Thread c = new Thread(mythread, "C"); 14 Thread d = new Thread(mythread, "D"); 15 Thread e = new Thread(mythread, "E"); 16 17 a.start(); 18 b.start(); 19 c.start(); 20 d.start(); 21 e.start(); 22 23 24 } 25 }
1 D:itjdk1.8injava -Didea.launcher.port=7534 "-Didea.launcher.bin.path=D:itideaIntelliJ IDEA 2016.3.3in" -Dfile.encoding=UTF-8 -classpath "D:itjdk1.8jrelibcharsets.jar;D:itjdk1.8jrelibdeploy.jar;D:itjdk1.8jrelibextaccess-bridge-64.jar;D:itjdk1.8jrelibextcldrdata.jar;D:itjdk1.8jrelibextdnsns.jar;D:itjdk1.8jrelibextjaccess.jar;D:itjdk1.8jrelibextjfxrt.jar;D:itjdk1.8jrelibextlocaledata.jar;D:itjdk1.8jrelibext ashorn.jar;D:itjdk1.8jrelibextsunec.jar;D:itjdk1.8jrelibextsunjce_provider.jar;D:itjdk1.8jrelibextsunmscapi.jar;D:itjdk1.8jrelibextsunpkcs11.jar;D:itjdk1.8jrelibextzipfs.jar;D:itjdk1.8jrelibjavaws.jar;D:itjdk1.8jrelibjce.jar;D:itjdk1.8jrelibjfr.jar;D:itjdk1.8jrelibjfxswt.jar;D:itjdk1.8jrelibjsse.jar;D:itjdk1.8jrelibmanagement-agent.jar;D:itjdk1.8jrelibplugin.jar;D:itjdk1.8jrelib esources.jar;D:itjdk1.8jrelib t.jar;F:springboot hreaddemooutproduction hreaddemo;D:itideaIntelliJ IDEA 2016.3.3libidea_rt.jar" com.intellij.rt.execution.application.AppMain com.cky.test.Test3 2 由A计算count=3 3 由D计算count=0 4 由E计算count=1 5 由C计算count=2 6 由B计算count=3 7 8 Process finished with exit code 0
结果分析,上面将一个线程对象传递到其他的线程中进行调用,相当于一个多个线程实例调用同一个线程对象,共享线程对象中的变量。
结果中A和B同时输出3,实际我们想要的结果是依次递减,产生了非线程安全的问题。
由于线程执行的随机性,所以产生了这样的结果,这时就需要让多个线程进行同步,也就是按顺序执行run方法里的内容,就是让一个线程执行完run方法里的代码后,再让cpu切换到另一个线程
使用synchronized关键字
1 package com.cky.thread; 2 3 /** 4 * Created by chenkaiyang on 2017/11/27. 5 */ 6 public class MyThreadThird extends Thread{ 7 private int count = 5; 8 @Override 9 synchronized public void run() { 10 super.run(); 11 count -- ; 12 System.out.println("由" + this.currentThread().getName()+"计算count="+count); 13 } 14 }
再执行上面的test,结果如下(说明线程安全了)
D:itjdk1.8injava -Didea.launcher.port=7536 "-Didea.launcher.bin.path=D:itideaIntelliJ IDEA 2016.3.3in" -Dfile.encoding=UTF-8 -classpath "D:itjdk1.8jrelibcharsets.jar;D:itjdk1.8jrelibdeploy.jar;D:itjdk1.8jrelibextaccess-bridge-64.jar;D:itjdk1.8jrelibextcldrdata.jar;D:itjdk1.8jrelibextdnsns.jar;D:itjdk1.8jrelibextjaccess.jar;D:itjdk1.8jrelibextjfxrt.jar;D:itjdk1.8jrelibextlocaledata.jar;D:itjdk1.8jrelibext ashorn.jar;D:itjdk1.8jrelibextsunec.jar;D:itjdk1.8jrelibextsunjce_provider.jar;D:itjdk1.8jrelibextsunmscapi.jar;D:itjdk1.8jrelibextsunpkcs11.jar;D:itjdk1.8jrelibextzipfs.jar;D:itjdk1.8jrelibjavaws.jar;D:itjdk1.8jrelibjce.jar;D:itjdk1.8jrelibjfr.jar;D:itjdk1.8jrelibjfxswt.jar;D:itjdk1.8jrelibjsse.jar;D:itjdk1.8jrelibmanagement-agent.jar;D:itjdk1.8jrelibplugin.jar;D:itjdk1.8jrelib esources.jar;D:itjdk1.8jrelib t.jar;F:springboot hreaddemooutproduction hreaddemo;D:itideaIntelliJ IDEA 2016.3.3libidea_rt.jar" com.intellij.rt.execution.application.AppMain com.cky.test.Test3 由A计算count=4 由E计算count=3 由D计算count=2 由C计算count=1 由B计算count=0 Process finished with exit code 0
结果分析:
synchronized可以在任意对象及方法上枷锁,而加锁的这段代码叫做互斥区
总结:当一个线程想要执行同步方法里的代码,首先线程会尝试拿这把锁,如果能拿到这把锁,那么这个线程就能执行synchronize里的代码,如果拿不到这把锁,这个线程就会不断尝试那这把锁
,直到拿到为止,而且是多个线程同时去争抢这个锁
非线程安全:多个线程对同一个对象中的同一个实例变量进行操作出现值被更改,值不同步,出现影响程序执行流程的情况。