线程同步的方法

用什么关键字修饰同步方法 ? synchronized关键字修饰同步方法 java

 同步有几种实现方法,都是什么?分别是synchronized,waitnotify 多线程

wait():使一个线程处于等待状态,而且释放所持有的对象的lock
sleep():
使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InterruptedException异常。
notify():
唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM肯定唤醒哪一个线程,并且不是按优先级。
Allnotity():
唤醒全部处入等待状态的线程,注意并非给全部唤醒线程一个对象的锁,而是让它们竞争。 oop

实现同步的方式 this

同步是多线程中的重要概念。同步的使用能够保证在多线程运行的环境中,程序不会产生设计以外的错误结果。同步的实现方式有两种,同步方法和同步块,这两种方式都要用到synchronized关键字。 spa

给一个方法增长synchronized修饰符以后就可使它成为同步方法,这个方法能够是静态方法和非静态方法,可是不能是抽象类的抽象方法,也不能是接口中的接口方法。下面代码是一个同步方法的示例: 线程

public synchronized void aMethod() {  设计

    // do something  对象

接口

public static synchronized void anotherMethod() {  get

    // do something 

线程在执行同步方法时是具备排它性的。当任意一个线程进入到一个对象的任意一个同步方法时,这个对象的全部同步方法都被锁定了,在此期间,其余任何线程都不能访问这个对象的任意一个同步方法,直到这个线程执行完它所调用的同步方法并从中退出,从而致使它释放了该对象的同步锁以后。在一个对象被某个线程锁定以后,其余线程是能够访问这个对象的全部非同步方法的。

同步块是经过锁定一个指定的对象,来对同步块中包含的代码进行同步;而同步方法是对这个方法块里的代码进行同步而这种状况下锁定的对象就是同步方法所属的主体对象自身。若是这个方法是静态同步方法呢?那么线程锁定的就不是这个类的对象了,也不是这个类自身,而是这个类对应的java.lang.Class类型的对象。同步方法和同步块之间的相互制约只限于同一个对象之间,因此静态同步方法只受它所属类的其它静态同步方法的制约,而跟这个类的实例(对象)没有关系。

若是一个对象既有同步方法,又有同步块,那么当其中任意一个同步方法或者同步块被某个线程执行时,这个对象就被锁定了,其他线程没法在此时访问这个对象的同步方法,也不能执行同步块。

synchronized 关键字用于保护共享数据。请你们注意“共享数据”,你必定要分清哪些数据是共享数据,请看下面的例子:

public class ThreadTest implements Runnable{

public synchronized void run(){

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

System.out.print(" " + i);

}

}

public static void main(String[] args) {

Runnable r1 = new ThreadTest(); //也可写成ThreadTest r1 = new ThreadTest();

Runnable r2 = new ThreadTest();

Thread t1 = new Thread(r1);

Thread t2 = new Thread(r2);

t1.start();

t2.start();

}}

在这个程序中,run()虽然被加上了synchronized 关键字,但保护的不是共享数据。由于这个程序中的t1,t2 两个对象(r1,r2)的线程。而不一样的对象的数据是不一样的r1,r2 有各自的run()方法,因此输出结果没法预知。

synchronized的目的是使同一个对象的多个线程在某个时刻只有其中的一个线程能够访问这个对象的synchronized 数据每一个对象都有一个“锁标志”,当这个对象的一个线程访问这个对象的某个synchronized 数据时,这个对象的全部被synchronized 修饰的数据将被上锁(由于“锁标志”被当前线程拿走了),只有当前线程访问完它要访问的synchronized 数据时,当前线程才会释放“锁标志”,这样同一个对象的其它线程才有机会访问synchronized 数据。

示例3

public class ThreadTest implements Runnable{

public synchronized void run(){

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

System.out.print(" " + i);

}

}

public static void main(String[] args){

Runnable r = new ThreadTest();

Thread t1 = new Thread(r);

Thread t2 = new Thread(r);

t1.start();

t2.start();

}}

若是你运行1000 次这个程序,它的输出结果也必定每次都是:0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9。由于这里的synchronized 保护的是共享数据。t1,t2 是同一个对象(r)的两个线程,当其中的一个线程(例如:t1)开始执行run()方法时,因为run()synchronized保护,因此同一个对象的其余线程(t2)没法访问synchronized 方法(run 方法)。只有当t1执行完后t2 才有机会执行。

示例4

public class ThreadTest implements Runnable{

public void run(){

synchronized(this){

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

System.out.print(" " + i);

}} }

public static void main(String[] args){

Runnable r = new ThreadTest();

Thread t1 = new Thread(r);

Thread t2 = new Thread(r);

t1.start();

t2.start();

}}

这个程序与示例的运行结果同样。在可能的状况下,应该把保护范围缩到最小,能够用示例的形式,this 表明“这个对象”。没有必要把整个run()保护起来,run()中的代码只有一个for循环,因此只要保护for 循环就能够了。

示例5

public class ThreadTest implements Runnable{

public void run(){

for(int k=0;k<5;k++){

System.out.println(Thread.currentThread().getName()+ " : for loop : " + k);

}

synchronized(this){

for(int k=0;k<5;k++) {

System.out.println(Thread.currentThread().getName()+ " : synchronized for loop : " + k);

}} }

public static void main(String[] args){

Runnable r = new ThreadTest();

Thread t1 = new Thread(r,"t1_name");

Thread t2 = new Thread(r,"t2_name");

t1.start();

t2.start();

} }

运行结果:

t1_name : for loop : 0

t1_name : for loop : 1

t1_name : for loop : 2

t2_name : for loop : 0

t1_name : for loop : 3

t2_name : for loop : 1

t1_name : for loop : 4

t2_name : for loop : 2

t1_name : synchronized for loop : 0

t2_name : for loop : 3

t1_name : synchronized for loop : 1

t2_name : for loop : 4

t1_name : synchronized for loop : 2

t1_name : synchronized for loop : 3

t1_name : synchronized for loop : 4

t2_name : synchronized for loop : 0

t2_name : synchronized for loop : 1

t2_name : synchronized for loop : 2

t2_name : synchronized for loop : 3

t2_name : synchronized for loop : 4

第一个for 循环没有受synchronized 保护。对于第一个for 循环,t1,t2 能够同时访问。运行结果代表t1 执行到了k=2 时,t2 开始执行了。t1 首先执行完了第一个for 循环,此时t2尚未执行完第一个for 循环(t2 刚执行到k=2t1 开始执行第二个for 循环,当t1的第二个for 循环执行到k=1 时,t2 的第一个for 循环执行完了。t2 想开始执行第二个for 循环,但因为t1 首先执行了第二个for 循环,这个对象的锁标志天然在t1 手中(synchronized 方法的执行权也就落到了t1 手中),在t1 没执行完第二个for 循环的时候,它是不会释放锁标志的。因此t2 必须等到t1 执行完第二个for 循环后,它才能够执行第二个for 循环。

相关文章
相关标签/搜索