JAVA中线程同步的方法

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

 同步有几种实现方法,都是什么?分别是synchronized,wait与notify

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

实现同步的方式

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

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

public synchronized void aMethod() {

// do something

}

public static synchronized void anotherMethod() {

// 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();

}}

这个程序与示例3 的运行结果一样。在可能的情况下,应该把保护范围缩到最小,可以用示例4 的形式,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=2)。t1 开始执行第二个for 循环,当t1的第二个for 循环执行到k=1 时,t2 的第一个for 循环执行完了。t2 想开始执行第二个for 循环,但由于t1 首先执行了第二个for 循环,这个对象的锁标志自然在t1 手中(synchronized 方法的执行权也就落到了t1 手中),在t1 没执行完第二个for 循环的时候,它是不会释放锁标志的。所以t2 必须等到t1 执行完第二个for 循环后,它才可以执行第二个for 循环。

时间: 2024-10-06 05:01:21

JAVA中线程同步的方法的相关文章

JAVA中线程同步的方法(7种)汇总

一.同步方法 即有synchronized关键字修饰的方法. 由于java的每个对象都有一个内置锁,当用此关键字修饰方法时, 内置锁会保护整个方法.在调用该方法前,需要获得内置锁,否则就处于阻塞状态. 注: synchronized关键字也可以修饰静态方法,此时如果调用该静态方法,将会锁住整个类. 二.同步代码块 即有synchronized关键字修饰的语句块. 被该关键字修饰的语句块会自动被加上内置锁,从而实现同步 代码如: synchronized(object){ } 注:同步是一种高开销

Java中线程同步的理解 - 其实应该叫做Java线程排队

Java中线程同步的理解 我们可以在计算机上运行各种计算机软件程序.每一个运行的程序可能包括多个独立运行的线程(Thread). 线程(Thread)是一份独立运行的程序,有自己专用的运行栈.线程有可能和其他线程共享一些资源,比如,内存,文件,数据库等. 当多个线程同时读写同一份共享资源的时候,可能会引起冲突.这时候,我们需要引入线程"同步"机制,即各位线程之间要有个先来后到,不能一窝蜂挤上去抢作一团. 同步这个词是从英文synchronize(使同时发生)翻译过来的.我也不明白为什么

java中线程同步

最近用到线程同步,思路有点不是很清晰了,只记得synchronized和lock,其区别什么的记不清了.抽点空进行一下总结: lock接口 基本上拥有synchronized的所有功能 还提供了三种形式的锁获取(可中断.不可中断和定时)在其性能特征.排序保证或其他实现质量上可能会有所不同. 如线程A和B都要获取对象O的锁,A线程首先获取到了对象O的锁,那么B将要等待A释放对O的锁定 此时如果使用的是synchronized,若A不释放锁,B将会一直等下去,直到A释放对O的锁定 如果使用的是loc

java中线程同步问题

先不多说,直接上个例子,著名的生产者消费者问题. 1 public class ProducerConsumer { 2 public static void main(String[] args) { 3 SyncStack ss = new SyncStack(); 4 Producer p = new Producer(ss); 5 Consumer c = new Consumer(ss); 6 new Thread(p).start();//生产者线程 7 new Thread(c).

同步方法 sleep和wait 线程同步的方法

当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法? 分两种情况 1):进入此对象的非同步方法 答案:可以 2):进入此对象的同步方法 答案:不可以 sleep指线程被调用时,占着CPU不工作,形象地说明为"占着CPU睡觉",此时,系统的CPU部分资源被占用,其他线程无法进入,会增加时间限制.wait指线程处于进入等待状态,形象地说明为"等待使用CPU",此时线程不占用任何资源,不增加时间限制.所以sleep(100L)意

Java中线程的同步问题

在生活中我们时常会遇到同步的问题,而且大多数的实际问题都是线程的同步问题 我这里以生活中的火车售票来进行举例: 假设现在我们总共有1000张票要进行出售,共有10个出售点,那么当售票到最后只有一张票时,每个售票点如何去处理这唯一的一张票?或者对于某一张票而言,假设它正在售票站1售票的程序执行过程中,但是还没有出售,那么此时,其他售票站改如何去处理这张票呢? 这时,应该考虑使用java中的同步机制: 方法一:使用Runnable接口实现 package thread; public class T

JAVA之线程同步的三种方法

最近接触到一个图片加载的项目,其中有声明到的线程池等资源需要在系统中线程共享,所以就去研究了一下线程同步的知识,总结了三种常用的线程同步的方法,特来与大家分享一下.这三种方法分别是:synchronized代码段.synchronized修饰方法/类.ThreadLocal本地线程变量. 我们通过一个例子来表现这三种方法:一张银行卡里面有300块钱,15个线程从这张银行卡中取钱,每个线程取一次且每次取20块钱:当当前余额不足100元时,则向账户中汇款20元.三种方法每种方法都有5个线程.我们预期

Java中线程封闭之ThreadLocal

在访问共享数据时通常使用同步.若不使用同步则可以将对象封闭在一个线程中达到线程安全的目的,该方法称为线程封闭(Thread Confinement).其中实现线程封闭中规范的方法是使用ThreadLocal类.线程封闭技术一种常用的使用场景是在JDBC Connection对象. public class ConnectionHelper{private final static String URL = "";private final static ThreadLocal<C

Java 并发 线程同步

Java 并发 线程同步 @author ixenos 同步 1.异步线程本身包含了执行时需要的数据和方法,不需要外部提供的资源和方法,在执行时也不关心与其并发执行的其他线程的状态和行为 2.然而,大多数实际的多线程应用中,两个或两个以上的线程需要共享对同一数据的存取,这将产生同步问题(可见性和同步性的丢失) 比如两个线程同时执行指令account[to] += amount,这不是原子操作,可能被处理如下: a)将account[to]加载到寄存器 b)增加amount c)将结果写回acco