在Java中,同步是一种控制多线程访问共享资源的能力。当咱们只容许一个线程访问共享资源时同步是最好的选择。同步通常用来解决两个问题:1.防止线程干扰2.防止一致性问题。同步分两类:1.进程(Process)同步2.线程(Thread)同步。这里咱们只讨论Java中线程同步。html
当咱们在一个程序中启动两个或两个以上线程时,可能会有一种状况:当多个线程试图访问相同的资源时因为并发问题会产生没法预料的结果。举个例子:若是多个线程同时写同一个文件它们可能会破坏数据,由于其中一个线程会覆盖数据,或者当一个线程打开文件的同时另外一个线程正在关闭该文件。git
因此多线程要考虑同步问题,确保同一时间只有一个线程能够访问资源。这里就会有一个概念叫监视器(monitors),每一个对象(object)在Java中都关联一个监视器,每一个线程均可以加锁(lock)和解锁(unlock),但同一时间只有一个线程能够给监视器加锁或解锁。github
Java提供了一种很是简单的方式来建立和同步任务代码块:经过使用synchronized关键字。下面是同步的通常方式:算法
1 synchronized(objectidentifier) { 2 // 访问共享变量和其它共享资源 3 }
这里的objectidentifier指的是获取了锁的监视器的对象。下来咱们写两个例子,咱们将使用两个不一样的线程打印一个计数器。当没有线程同步时不是按顺序打印计数器的值,当使用synchronized()同步代码块时能够看到计数器打印的值是有序的。多线程
多线程示例:没有同步代码块并发
这是一个简单的例子。它可能但不必定会按顺序打印出计数器的值,这是由CPU的可用性决定的。ide
1 class PrintDemo { 2 public void printCount() { 3 try { 4 for(int i = 5; i > 0; i--) { 5 System.out.println("Counter --- " + i ); 6 } 7 }catch (Exception e) { 8 System.out.println("Thread interrupted."); 9 } 10 } 11 } 12 13 class ThreadDemo extends Thread { 14 private Thread t; 15 private String threadName; 16 PrintDemo PD; 17 18 ThreadDemo( String name, PrintDemo pd) { 19 threadName = name; 20 PD = pd; 21 } 22 23 public void run() { 24 PD.printCount(); 25 System.out.println("Thread " + threadName + " exiting."); 26 } 27 28 public void start () { 29 System.out.println("Starting " + threadName ); 30 if (t == null) { 31 t = new Thread (this, threadName); 32 t.start (); 33 } 34 } 35 } 36 37 public class TestThread { 38 public static void main(String args[]) { 39 40 PrintDemo PD = new PrintDemo(); 41 42 ThreadDemo T1 = new ThreadDemo( "Thread - 1 ", PD ); 43 ThreadDemo T2 = new ThreadDemo( "Thread - 2 ", PD ); 44 45 T1.start(); 46 T2.start(); 47 48 // wait for threads to end 49 try { 50 T1.join(); 51 T2.join(); 52 }catch( Exception e) { 53 System.out.println("Interrupted"); 54 } 55 } 56 }
执行上面的代码每次运行的结果可能不同,因此不能保证咱们按顺序打印计数器。this
多线程示例:使用同步代码块spa
下面是一样的一个例子,不过咱们加了synchronized()同步代码块,这样它每次都能按顺序打印相同的值。操作系统
1 class PrintDemo { 2 public void printCount() { 3 try { 4 for(int i = 5; i > 0; i--) { 5 System.out.println("Counter --- " + i ); 6 } 7 }catch (Exception e) { 8 System.out.println("Thread interrupted."); 9 } 10 } 11 } 12 13 class ThreadDemo extends Thread { 14 private Thread t; 15 private String threadName; 16 PrintDemo PD; 17 18 ThreadDemo( String name, PrintDemo pd) { 19 threadName = name; 20 PD = pd; 21 } 22 23 public void run() { 24 synchronized(PD) { 25 PD.printCount(); 26 } 27 System.out.println("Thread " + threadName + " exiting."); 28 } 29 30 public void start () { 31 System.out.println("Starting " + threadName ); 32 if (t == null) { 33 t = new Thread (this, threadName); 34 t.start (); 35 } 36 } 37 } 38 39 public class TestThread { 40 41 public static void main(String args[]) { 42 PrintDemo PD = new PrintDemo(); 43 44 ThreadDemo T1 = new ThreadDemo( "Thread - 1 ", PD ); 45 ThreadDemo T2 = new ThreadDemo( "Thread - 2 ", PD ); 46 47 T1.start(); 48 T2.start(); 49 50 // wait for threads to end 51 try { 52 T1.join(); 53 T2.join(); 54 }catch( Exception e) { 55 System.out.println("Interrupted"); 56 } 57 } 58 }
执行上面的代码每次打印的结果都同样:按顺序输出计数器的值。
Java多任务处理都会有并发执行状况,多个任务或进程共享一个CPU,并交由操做系统来完成多任务间对CPU的运行切换,以使得每一个任务都有机会得到必定的时间片运行。下面是并发和并行的区别:Concurrent and Parallel Programming
并发:两个队列一个咖啡机。一个CPU处理多个任务逻辑,经过CPU调度算法分配计算资源,非真正的同时进行。
并行:两个队列两个咖啡机。多个CPU处理多个任务逻辑,多个计算任务能够同时进行。