java学习的道路上呢总有一些麻烦的东西需要花费一些时间去理解,比如个人认为不好搞的多线程.
线程是并列运行的
因为是并列运行,所以有时候会发生资源抢占,从而导致参数变化;
比如酱紫
package seer.线程; public class SumArray { private int sum; //在这个地方sumArry()没有被同步 没有加sync... public int sumArray(int[] sums) { sum = 0; //重置 初始化sum for (int i = 0; i < sums.length; i++) { sum += sums[i]; try { Thread.sleep(10); //发生任务切换时,有意允许切换的发生(如果加了synchronized就绝对不可能发生了.) } catch (InterruptedException e) { System.out.println("线程中断"); e.printStackTrace(); } } return sum; } } //=========================================================================================================== class MyThread implements Runnable { Thread thrd; static SumArray sa = new SumArray(); int[] a; int answer; //构造一个线程 public MyThread(String name, int[] nums) { thrd = new Thread(this, name); a = nums; } //创建一个工厂方法用来创建和启动线程 public static MyThread createAndStart(String name, int[] nums) { MyThread myThrd = new MyThread(name, nums); myThrd.thrd.start(); return myThrd; } @Override public void run() { int sum; System.out.println(thrd.getName() + "启动"); //这里,在sa对象上对sumArray的调用进行同步 // synchronized (sa) { answer = sa.sumArray(a); System.out.println(thrd.getName() + "计算的结果是:" + answer); // } System.out.println(thrd.getName()+"结束"); } } //=========================================================================================================== //创建一个拥有main函数的类 class Sync{ public static void main(String[] args) { int[] arr = {2, 3, 2, 3, 2}; MyThread myt = MyThread.createAndStart("线程1", arr); MyThread myt1 = MyThread.createAndStart("线程2", arr); } }
线程2启动
线程1启动
线程1计算的结果是:22
线程2计算的结果是:22
线程1结束
线程2结束
//ps 结果是22 原因是因为有一个sleep,这样才能更客观的发现两个线程的区别
创建了两个线程,两个线程不分先后的执行一个方法,由于线程的并行特性,会发生两个线程同时进入一个方法的情况, 这时候就会可能会导致数据操作次数改变,从而直接影响结果.
有两个方法:
方法1:
在sumArray()方法上加synchronized关键字,加上这个关键字后的sumArray()学名叫做"同步方法"
public synchronized int sumArray(int[] sums) { sum = 0; //重置 / 初始化sum for (int i = 0; i < sums.length; i++) { sum += sums[i]; try { Thread.sleep(20); } catch (InterruptedException e) { System.out.println("线程中断"); e.printStackTrace(); } } return sum; }
加上synchronized ,不管在什么样的线程情况下,可以保证每一次只能由一个线程进入这个方法,其他线程排队等待,直到当前线程执行完毕才可以进入.
方法2
使用同步语句
static SumArray sa = new SumArray();
public void run() { int sum; System.out.println(thrd.getName() + "启动"); synchronized (sa) {//这一段 answer = sa.sumArray(a); System.out.println(thrd.getName() + "计算的结果是:" + answer); } System.out.println(thrd.getName()+"结束"); }
同步语句的基本格式:
synchronized(ref){
//方法体
}
这里的ref是被同步对象的引用,上文代码中就直接引用的一个普通对象
两种方法都可以实现方法的同步阻止多线程的环境下造成数据紊乱的情况
那么同步方法和同步语句的区别在哪呢?
虽然同步方法时实现同步的一种简单有效的方法,但这方法并不适用于所有情况,
例如:可能需要对某些不被synchronized修改的方法进行同步.在想使用有第三方创建的类,而无法访问源代码时就会出现这样的情况.
这个时候使用同步代码块
各有所需,两种用法,作用相同.