java java多线程如何确定线程数 两个线程访问两个对象中不同的synchronized修饰的方法。(方法和对象都是同一个类的)

java多线程并发访问解决方案
我的图书馆
java多线程并发访问解决方案
java多线程并发访问解决方案
多线程并发访问解决方案
synchronized关键字主要解决多线程共享数据同步问题。
ThreadLocal使用场合主要解决多线程中数据因并发产生不一致问题。
ThreadLocal和Synchonized都用于解决多线程并发访问。但是ThreadLocal与synchronized有本质的区别。synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通信时能够获得数据共享。
Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。
当然ThreadLocal并不能替代synchronized,它们处理不同的问题域。Synchronized用于实现同步机制,比ThreadLocal更加复杂。
java中synchronized用法
使用了synchronized关键字可以轻松地解决多线程共享数据同步问题。
&synchronized关键字可以作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块。如果再细的分类,synchronized可作用于instance变量、object
reference(对象引用)、static函数和class literals(类名称字面常量)身上。&
synchronized取得的锁都是对象;每个对象只有一个锁(lock)与之相关联;实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。
方法声明时使用,线程获得的是成员锁.
对某一代码块使用,synchronized后跟括号,括号里是变量,线程获得的是成员锁.
3.synchronized后面括号里是一对象,此时,线程获得的是对象锁.
4.synchronized后面括号里是类,此时,线程获得的是对象锁.&
synchronized的使用还是有一些细节问题要注意的。
1.synchronized与static synchronized
synchronized是对类的当前实例进行加锁,防止其他线程同时访问该类的该实例的所有synchronized块,注意这里是“类的当前实例”,类的两个不同实例就没有这种约束了。那么static
synchronized恰好就是要控制类的所有实例的访问了,static
synchronized是限制线程同时访问jvm中该类的所有实例同时访问对应的代码快。实际上,在类中某方法或某代码块中有synchronized,那么在生成一个该类实例后,改类也就有一个监视快,放置线程并发访问改实例synchronized保护快,而static
synchronized则是所有该类的实例公用一个监视快了,也也就是两个的区别了,也就是synchronized相当于this.synchronized,而
static synchronized相当于Something.synchronized.
一个日本作者-结成浩的《java多线程设计模式》有这样的一个列子:
pulbic class Something(){
public synchronized void isSyncA(){}
public synchronized void isSyncB(){}
public static synchronized void cSyncA(){}
public static synchronized void cSyncB(){}
那么,加入有Something类的两个实例a与b,那么下列组方法何以被1个以上线程同时访问呢
x.isSyncA()与x.isSyncB()
x.isSyncA()与y.isSyncA()
c.&& x.cSyncA()与y.cSyncB()
x.isSyncA()与Something.cSyncA()
这里,很清楚的可以判断:
a,都是对同一个实例的synchronized域访问,因此不能被同时访问
&& b,是针对不同实例的,因此可以同时被访问
&& c,因为是static
synchronized,所以不同实例之间仍然会被限制,相当于Something.isSyncA()与&&
Something.isSyncB()了,因此不能被同时访问。
那么,第d呢?,书上的答案是可以被同时访问的,答案理由是synchronzied的是实例方法与synchronzied的类方法由于锁定(lock)不同的原因。
&& 个人分析也就是synchronized 与static
synchronized
相当于两帮派,各自管各自,相互之间就无约束了,可以被同时访问。目前还不是分清楚java内部设计synchronzied是怎么样实现的。
&&& 结论:A: synchronized static是某个类的范围,synchronized
cSync{}防止多个线程同时访问这个&&&
类中的synchronized static 方法。它可以对类的所有对象实例起作用。
&&&&&&&&&&&&&&
B: synchronized 是某实例的范围,synchronized
isSync(){}防止多个线程同时访问这个实例中的synchronized 方法。
2.synchronized方法与synchronized代码快的区别
&&&&&假设P1、P2是同一个类的不同对象,这个类中定义了以下几种情况的同步块或同步方法,P1、P2就都能够调用他们。
Java的synchronized使用方法总结
把synchronized当作函数修饰符时,示例代码如下:
Public&synchronized&void&method(){&
这也就是同步方法,那这时synchronized锁定的是哪个对象呢?他锁定的是调用这个同步方法对象。也就是说,当一个对象P1在不同的线程中执行这个同步方法时,他们之间会形成互斥,达到同步的效果。但是这个对象所属的Class所产生的另一对象P2却能够任意调用这个被加了synchronized关键字的方法。
上边的示例代码等同于如下代码:
public&void&method()&
synchronized&(this)&&&&&&//&&(1)&
&&&&&&&//…..&
(1)处的this指的是什么呢?他指的就是调用这个方法的对象,如P1。可见同步方法实质是将synchronized作用于object
reference。――那个拿到了P1对象锁的线程,才能够调用P1的同步方法,而对P2而言,P1这个锁和他毫不相干,程式也可能在这种情形下摆脱同步机制的控制,造成数据混乱。
2.同步块,示例代码如下:
public&void&method(SomeObject&so)&{&
synchronized(so)&
&&&&&&&//…..&
这时,锁就是so这个对象,谁拿到这个锁谁就能够运行他所控制的那段代码。当有一个明确的对象作为锁时,就能够这样写程式,但当没有明确的对象作为锁,只是想让一段代码同步时,能够创建一个特别的instance变量(他得是个对象)来充当锁:
class&Foo&implements&Runnable&
&&&&&&&private&byte[]&lock&=&new&byte[0];&&//&特别的instance变量&
&&&&Public&void&method()&
&&&&&&&synchronized(lock)&{&//…&}&
注:零长度的byte数组对象创建起来将比任何对象都经济――查看编译后的字节码:生成零长度的byte[]对象只需3条操作码,而Object
lock = new Object()则需要7行操作码。
3.将synchronized作用于static 函数,示例代码如下:
&&&&&&Class&Foo&
public&synchronized&static&void&method1()&&&//&同步的static&函数&
public&void&method2()&
&&&&&&&synchronized(Foo.class)&&&//&&class&literal(类名称字面常量)&
代码中的method2()方法是把class
literal作为锁的情况,他和同步的static函数产生的效果是相同的,取得的锁很特别,是当前调用这个方法的对象所属的类(Class,而不再是由这个Class产生的某个具体对象了)。
记得在《Effective Java》一书中看到过将 Foo.class和
P1.getClass()用于作同步锁还不相同,不能用P1.getClass()来达到锁这个Class的目的。P1指的是由Foo类产生的对象。
能够推断:假如一个类中定义了一个synchronized的static函数A,也定义了一个synchronized
的instance函数B,那么这个类的同一对象Obj在多线程中分别访问A和B两个方法时,不会构成同步,因为他们的锁都不相同。A方法的锁是Obj所属的那个Class,而B的锁是Obj所属的这个对象。
Java的synchronized使用方法小结如下:
搞清楚synchronized锁定的是哪个对象,就能帮助我们设计更安全的多线程程式。
更有一些技巧能够让我们对共享资源的同步访问更加安全:
1.& 定义private 的instance变量+他的
get方法,而不要定义public/protected的instance变量。假如将变量定义为public,对象在外界能够绕过同步方法的控制而直接取得他,并改变他。这也是JavaBean的标准实现方式之一。
假如instance变量是个对象,如数组或ArrayList什么的,那上述方法仍然不安全,因为当外界对象通过get方法拿到这个instance对象的引用后,又将其指向另一个对象,那么这个private变量也就变了,岂不是很危险。这个时候就需要将get方法也加上synchronized同步,并且,只返回这个private对象的clone()――这样,调用端得到的就是对象副本的引用了。
java.lang.ThreadLocal()的用法
ThreadLocal是什么呢?其实ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,而是threadlocalvariable(线程局部变量)。也许把它命名为ThreadLocalVar更加合适。线程局部变量(ThreadLocal)其实的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是Java中一种较为特殊的线程绑定机制,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。
ThreadLocal是如何做到为每一个线程维护变量的副本的呢?其实实现的思路很简单,在ThreadLocal类中有一个Map,用于存储每一个线程的变量的副本。
概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。
二、API说明
ThreadLocal()
创建一个线程本地变量。
返回此线程局部变量的当前线程副本中的值,如果这是线程第一次调用该方法,则创建并初始化此副本。
protected T
initialValue()
返回此线程局部变量的当前线程的初始值。最多在每次访问线程来获得每个线程局部变量时调用此方法一次,即线程第一次使用
get() 方法访问变量的时候。如果线程先于 get 方法调用 set(T) 方法,则不会在线程中再调用
initialValue 方法。
若该实现只返回
如果程序员希望将线程局部变量初始化为 null 以外的某个值,则必须为 ThreadLocal
创建子类,并重写此方法。通常,将使用匿名内部类。initialValue
的典型实现将调用一个适当的构造方法,并返回新构造的对象。
void remove()
移除此线程局部变量的值。这可能有助于减少线程局部变量的存储需求。如果再次访问此线程局部变量,那么在默认情况下它将拥有其
initialValue。
void set(T
将此线程局部变量的当前线程副本中的值设置为指定值。许多应用程序不需要这项功能,它们只依赖于
initialValue() 方法来设置线程局部变量的值。
在程序中一般都重写initialValue方法,以给定一个特定的初始值。
三、典型实例
ThreadLocal使用场合主要解决多线程中数据因并发产生不一致问题。
ThreadLocal为每个线程的中并发访问的数据提供一个副本,通过访问副本来运行业务,这样的结果是耗费了内存,单大大减少了线程同步所带来性能消耗,也减少了线程并发控制的复杂度。
ThreadLocal不能使用原子类型,只能使用Object类型。ThreadLocal的使用比synchronized要简单得多。
五、ThreadLocal使用的一般步骤
1、在多线程的类(如ThreadDemo类)中,创建一个ThreadLocal对象threadXxx,用来保存线程间需要隔离处理的对象xxx。
2、在ThreadDemo类中,创建一个获取要隔离访问的数据的方法getXxx(),在方法中判断,若ThreadLocal对象为null时候,应该new()一个隔离访问类型的对象,并强制转换为要应用的类型。
3、在ThreadDemo类的run()方法中,通过getXxx()方法获取要操作的数据,这样可以保证每个线程对应一个数据对象,在任何时刻都操作的是这个对象。
喜欢该文的人也喜欢多线程中Synchronized来标记run()方法的问题 - ITeye问答
若将线程类的方法 run() 声明为 synchronized ,由于在线程的整个生命期内它一直在运行,因此将导致它对本类任何 synchronized 方法的调用都永远不会成功。
这段话怎么理解?能否帮我写一个程序以助于理解一下呢?
采纳的答案
哪里看到的? ms在java中对Thread类的run方法加synchronized 并不会锁住对象:
public class MyExtendThread extends Thread {
private int count = 1,
public MyExtendThread(int num) {
System.out.println("Create Thread-" + number);
public synchronized void run() {
while (true) {
System.out.println("Thread-" + number + " run " + count
+ " time(s)");
if (++count == 3)
public synchronized void canRun() {
sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("========");
public class TestThread {
public static void main(String[] args) {
MyExtendThread thread = new MyExtendThread(1);
thread.start();
thread.canRun();
System.out.println("end");
Create Thread-1
Thread-1 run 1 time(s)
Thread-1 run 2 time(s)
线程类的canRun方法还是执行了。
已解决问题
未解决问题【图文】java线程同步Synchronized_百度文库
您的浏览器Javascript被禁用,需开启后体验完整功能,
享专业文档下载特权
&赠共享文档下载特权
&100W篇文档免费专享
&每天抽奖多种福利
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
java线程同步Synchronized
阅读已结束,下载本文到电脑
定制HR最喜欢的简历
你可能喜欢java多线程(对象和变量的并发访问)
在现实开发中,我们写的线程肯定会有不同的实例在执行,此时就可能会出现&非线程安全问题&,非线程安全就是:多个线程对同一个对象中的实例变量进行并发访问时候,有可能A和B线程同时读取到数据,先后进行更改,此时,该变量就不是我们期望的数据,也就是通常所说的&脏数据&
实例变量非线程安全
需要注意的是,方法中的变量是不存在非线程安全问题的,这是因为方法内部的变量都是私有的。 如果多个线程共同访问了一个对象中的实例变量,则可能会出现线程安全问题。看下面代码:
public class MultiThreadSet {
public void setCount(String countStr) {
if (&first&.equals(countStr)) {
count = 100;
System.out.println(&first set over...&);
count = 200;
System.out.println(&second set over...&);
System.out.println(&setCount is :&+count);
public static void main(String[] args) {
MultiThreadSet multiThreadSet = new MultiThreadSet();
ThreadA threadA = new ThreadA(multiThreadSet);
ThreadB threadB = new ThreadB(multiThreadSet);
threadA.start();
threadB.start();
此时执行程序,结果如下:
synchronized public void setCount(String countStr) {
if (&first&.equals(countStr)) {
count = 100;
System.out.println(&first set over...&);
count = 200;
System.out.println(&second set over...&);
System.out.println(countStr + &setCount is :&+count);
可以看到,当多个线程访问同一对象中的同步方法时候,一定是线程安全的,那么如果是多个线程访问多个对象的同步方法,会是怎样呢?我们拭目以待:
MultiThreadSet multiThreadSetFirst = new MultiThreadSet();
MultiThreadSet multiThreadSetSecond = new MultiThreadSet();
ThreadA threadA = new ThreadA(multiThreadSetFirst);
ThreadB threadB = new ThreadB(multiThreadSetSecond);
threadA.start();
threadB.start();
以上是两个线程分别访问同一个类的多个不同实例相同的同步方法,结果却是以异步的方式执行的
多个线程访问多个对象,JVM会创建多个锁,上关键字synchronized 取得的锁都是对象锁,哪个线程先执行带synchronized 关键字的方法,哪个线程就持有该方法所属的对象锁,那么其他线程只能等待,前提是多个线程访问的是同一个对象
下面创建一个类,包含两个方法,一个使用synchronized修饰,一个是普通方法:
public class SyncLockMethod {
synchronized public void methodA() {
System.out.println(&methodA runs begin...... thread name is :&+Thread.currentThread().getName());
Thread.sleep(3000);
System.out.println(&methodA runs end......&);
} catch (InterruptedException e) {
e.printStackTrace();
public void methodB() {
System.out.println(&methodB runs begin======thread name is :&+Thread.currentThread().getName());
Thread.sleep(3000);
System.out.println(&methodB runs end======&);
} catch (InterruptedException e) {
e.printStackTrace();
分别创建两个线程ThreadA和ThreadB,然后在两个线程中调用不同的方法。
public class ThreadA extends Thread {
private SyncLockMethod syncLockM
public ThreadA(SyncLockMethod syncLockMethod) {
this.syncLockMethod = syncLockM
public void run() {
syncLockMethod.methodA();
// =================================================
public class ThreadB extends Thread {
private SyncLockMethod syncLockM
public ThreadB(SyncLockMethod syncLockMethod) {
this.syncLockMethod = syncLockM
public void run() {
syncLockMethod.methodB();
创建SyncLockMethod 类的一个实例对象,分别传入两个线程中去执行该对象中的不同方法:
public static void main(String[] args) {
SyncLockMethod syncLockMethod = new SyncLockMethod();
MultiThreadSet multiThreadSetSecond = new MultiThreadSet();
ThreadA threadA = new ThreadA(syncLockMethod);
ThreadB threadB = new ThreadB(syncLockMethod);
threadA.start();
threadB.start();
此时运行结果如下:
此时,我将methodB也改为同步方法:
synchronized public void methodB() {
System.out.println(&methodB runs begin======thread name is :&+Thread.currentThread().getName());
Thread.sleep(3000);
System.out.println(&methodB runs end======&);
} catch (InterruptedException e) {
e.printStackTrace();
在执行上面的操作,结果如下:
根据上面的对比操作,总结以下:
A线程先持有object对象的lock锁,B线程可以以异步的方式调用object对象中的非synchronized类型的方法 A线程先持有object对象的lock锁,B线程如果在这时调用object对象中的synchronized类型的方法,则需要等待
synchronized锁重入
synchronized锁重入:指的是当一个线程得到一个对象锁之后,再次请求该对象锁时候,可以再次得到该对象的锁。 看下面的栗子:
public class SynchronizedAgainService {
public synchronized void methodA() {
System.out.println(&methodA runs .......&);
methodB();
public synchronized void methodB() {
System.out.println(&methodB runs ========&);
methodC();
public synchronized void methodC() {
System.out.println(&methodC runs +++++++++&);
// =================================================
public class SynchronizedAgainThread extends Thread {
public void run() {
SynchronizedAgainService service = new SynchronizedAgainService();
service.methodA();
public static void main(String[] args) {
new SynchronizedAgainThread().start();
此时执行结果如下:
可以看到当一个线程获得了某个对象的锁,此时这个对象的锁还没有释放,此时依然可以再次获得该对象撒花姑娘的锁,另外当存在父子类继承关系时候,子类完全可以通过&可重入锁&调用父类中的同步方法。
synchronized同步代码块
当两个并发线程访问同一个对象object中的synchronized(this)同步代码块时,一段时间内,只能有一个线程被执行,另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
public class SubService {
public void printService() {
// synchronized同步代码块,
synchronized (this) {
System.out.println(&begin ParentSerice current name is :&+Thread.currentThread().getName());
Thread.sleep(2000);
System.out.println(&end ParentSerice current name is :&+Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
// =============================================
public class ThreadA extends Thread {
private SubService subS
public ThreadA(SubService subService) {
this.subService = subS
public void run() {
subService.printService();
// =============================================
public static void main(String[] args) {
SubService subService = new SubService();
ThreadA threadA = new ThreadA(subService);
ThreadB threadB = new ThreadB(subService);
threadA.setName(&threadA&);
threadB.setName(&threadB&);
threadA.start();
threadB.start();
此时运行结果如下:
可以看到上面的代码使用了synchronized代码块,是的线程得以同步运行,但是执行效率还是很低下的。可以将需要同步的代码块最小化,使用synchronized包裹起来。
需要注意的是:同步synchronized(this)代码块锁定的是当前对象,当多个线程调用同一个对象中的不同名称的synchronized同步方法或者synchronized(this)同步代码块时候,调用的效果是按顺序执行的,也就是同步的。
将任意对象作为对象监视器
我们可以使用synchronized(非this对象)来同步代码块
在多个线程持有&对象监视器&为同一个对象的前提下,同一时间只有一个线程可以执行synchronized(非this对象)同步代码块汇总的代码
public class MyService {
// 使用全局的anyString对象作为synchronized的对象监视器,由于是全局的,所以在synchronized (anyString)中使用的是同一个监视器
private String anyString = new String();
public void setNamePass(String name,String pass) {
synchronized (anyString) { // 同步代码块,如果是同一个对象监视器,则是同步执行的
System.out.println(&begin the thread name is :&+Thread.currentThread().getName());
this.name =
Thread.sleep(3000);
this.pass =
System.out.println(&end the thread name is :&+Thread.currentThread().getName()+&
name is :&+name+&
pass is :&+pass);
} catch (InterruptedException e) {
e.printStackTrace();
// ====================================================
public class ThreadA extends Thread {
private MyService myS
public ThreadA(MyService myService) {
this.myService = myS
public void run() {
myService.setNamePass(&aaa&, &aaapass&);
// =================================================
public class ThreadB extends Thread {
private MyService myS
public ThreadB(MyService myService) {
this.myService = myS
public void run() {
myService.setNamePass(&bbb&, &bbbpass&);
// ==============================================
public static void main(String[] args) {
MyService myService = new MyService();
ThreadA threadA = new ThreadA(myService);
ThreadB threadB = new ThreadB(myService);
threadA.setName(&threadA&);
threadB.setName(&threadB&);
threadA.start();
threadB.start();
此时程序执行结果如下:
可以看到,由于这里使用了全局的对象作为对象监视器,所以不同的线程进来执行的同一对象方法,即是相同的对象监视器。所以可以做到代码开同步。下面我们将anyString放到setNamePass方法内部,看下效果:
public void setNamePass(String name,String pass) {
// 这里不管是否调用的是同一对象的setNamePass方法,都会创建anyString对象,所以是没有办法做到代码块同步的。
String anyString = new String();
synchronized (anyString) { // 同步代码块,如果是同一个对象监视器,则是同步执行的
System.out.println(&begin the thread name is :&+Thread.currentThread().getName());
this.name =
Thread.sleep(3000);
this.pass =
System.out.println(&end the thread name is :&+Thread.currentThread().getName()+&
name is :&+name+&
pass is :&+pass);
} catch (InterruptedException e) {
e.printStackTrace();
此时执行结果如下:
可以看到,使用synchronized(非this对象)同步代码块时候,如果对象监视器不是同一个对象,运行的结果就是异步调用了。
这里,锁如果不是this对象,也有一定的有点,试想如果一个类中有很多synchronized方法,这时候,虽然能够实现同步,但是一个方法会阻塞其他方法的执行,但是如果使用同步代码块锁非this对象,则synchronized(非this) 代码块中的程序与同步方法是异步的,不与其他锁this同步方法争抢this锁,可以提高效率。
总结一下:
- 当多个线程同时执行synchronized(x) {}同步代码块时候,呈同步效果,前提是这多个线程必须要是同一个对象监视器
- 当其他线程执行x对象中synchronized同步方法时呈同步效果
- 当其他线程执行x对象方法里面的synchronized(this)代码块时,也呈现同步效果。
静态同步synchronized方法
关键字synchronized还可以应用在static静态方法上,如果这样,那么就是对当前的&*.java&对应的class类进行持锁。
public class MyService {
synchronized public static void printA() {
printInfo(&printA&);
synchronized public static void printB() {
printInfo(&printB&);
private static void printInfo(String methodName) {
String anyString = new String();
System.out.println(&begin &+methodName+& the thread name is :&+Thread.currentThread().getName());
Thread.sleep(3000);
System.out.println(&end &+methodName+& the thread name is :&+Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
// ====================================================
public class ThreadA extends Thread {
private MyService myS
public ThreadA(MyService myService) {
this.myService = myS
public void run() {
myService.printA();
// ===================================================
public class ThreadB extends Thread {
private MyService myS
public ThreadB(MyService myService) {
this.myService = myS
public void run() {
myService.printB();
// ====================================================
public static void main(String[] args) {
MyService myServiceFirst = new MyService();
MyService myServiceSecond = new MyService();
ThreadA threadA = new ThreadA(myServiceFirst);
ThreadB threadB = new ThreadB(myServiceSecond);
threadA.setName(&threadA&);
threadB.setName(&threadB&);
threadA.start();
threadB.start();
可以看到,上面在Myservice类中为printA和printB两个静态方法添加了synchronized,此时持有的就是当前class类的锁。这里由于是同一个锁,所以是同步打印的。
同步synchronized方法无限等待
同步方法容易造成死循环,其实说到底,还是多个线程持有的锁是一样的。看下面代码:
public class MyService {
synchronized public void printA() {
System.out.println(&printA beign...&);
boolean isContinue =
while (isContinue) {
System.out.println(&printA end...&);
synchronized public void printB() {
System.out.println(&printB beign...&);
System.out.println(&printB end...&);
此时打印结果如下:
可以看到程序走到这里进入了无线等待的状态,这是由于这里使用的是同一个对象作为锁,在printA方法中进入了无限循环的等待状态,此时没有释放锁,因此printB方法也不能获得当前锁,无法执行。因此我们只需要使用同步代码块,让两个方法,持有不同的锁对象
public class MyService {
private Object objA = new Object();
public void printA() {
synchronized (objA) {
System.out.println(&printA beign...&);
boolean isContinue =
while (isContinue) {
System.out.println(&printA end...&);
private Object objB = new Object();
public void printB() {
synchronized (objB) {
System.out.println(&printB beign...&);
System.out.println(&printB end...&);
多线程死锁
java多线程是一个经典的多线程问题,因为不同的线程都在等待根本不可能被释放的锁,从而导致所有的任务都无法继续完成。下面代码演示两个同步代码块互相等待对象释放锁,从而导致死锁的问题。
public class DeadThread extends Thread {
private Object lockFirst = new Object();
private Object lockSecond = new Object();
private String userN
public void setUserName(String userName) {
this.userName = userN
public void run() {
if (&aaa&.equals(userName)) {
synchronized (lockFirst) {
System.out.println(&username is :&+userName);
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
synchronized (lockSecond) {
System.out.println(&lockfirst ------&locksecond&);
if (&bbb&.equals(userName)) {
synchronized (lockSecond) {
System.out.println(&username is :&+userName);
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
synchronized (lockFirst) {
System.out.println(&locksecond ------&lockfirst&);
public static void main(String[] args) {
DeadThread deadThreadFirst = new DeadThread();
deadThreadFirst.setUserName(&aaa&);
deadThreadFirst.start();
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
DeadThread deadThreadSecond = new DeadThread();
deadThreadSecond.setUserName(&bbb&);
deadThreadSecond.start();
可以看到,两个if分支中的synchronized代码块,分别等待对象释放锁,就出现了死锁现象。
内部类与同步
测试:同步代码块synchronized(class2)对class2上锁以后,其他线程只能以同步的方式调用class2中的静态同步方法。
public class OutClass {
static class InnerClass1 {
public void method1(InnerClass2 class2) {
String threadName = Thread.currentThread().getName();
synchronized (class2) {
System.out.println(threadName+& 进入InnerClass1类的method1方法&);
for (int i = 0; i & 10; i++) {
System.out.println(&i = &+i);
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println(threadName+& 离开InnerClass1类的method1方法&);
public void method2() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName+& 进入InnerClass1类的method2方法&);
for (int i = 0; i & 10; i++) {
System.out.println(&i = &+i);
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println(threadName+& 离开InnerClass1类的method2方法&);
static class InnerClass2 {
public synchronized void method1() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName+& 进入InnerClass1类的method2方法&);
for (int i = 0; i & 10; i++) {
System.out.println(&i = &+i);
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println(threadName+& 离开InnerClass1类的method2方法&);
public static void main(String[] args) {
InnerClass1 in1 = new InnerClass1();
InnerClass2 in2 = new InnerClass2();
Thread t1 = new Thread(new Runnable() {
public void run() {
in1.method1(in2);
Thread t2 = new Thread(new Runnable() {
public void run() {
in1.method2();
Thread t3 = new Thread(new Runnable() {
public void run() {
in2.method1();
t1.start();
t2.start();
t3.start();
此时程序运行结果如下:
锁对象的改变
需要注意的是:在将任何数据类型作为同步锁时候,当多个线程同时持有锁对象,如果同时持有相同的锁对象,则这些线程之间就是同步的,如果分别获得锁对象,则这些线程之间就是异步的。看下面的栗子:
public class MyService {
private String mLock = &aaa&;
public void printInfo() {
synchronized (mLock) {
mLock = &bbb&;
System.out.println(&begin &+Thread.currentThread().getName()+& the thread name is :&+Thread.currentThread().getName());
Thread.sleep(3000);
System.out.println(&end &+Thread.currentThread().getName()+& the thread name is :&+Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
public static void main(String[] args) {
MyService myService = new MyService();
ThreadA threadA = new ThreadA(myService);
ThreadB threadB = new ThreadB(myService);
threadA.setName(&threadA&);
threadB.setName(&threadB&);
threadA.start();
threadB.start();
此时运行效果如下:
可以看到,此时threadA和threadB由于在同步块内部更改了锁对象,因此两个线程持有的锁是不同的,所以是异步执行的。
另外需要注意的是,只要对象不变,及时对象的属性被改变,运行的结果还是同步的。
volatile关键字
volatile关键字的主要作用是使变量在多个线程之间可见。volatile会强制从公共堆栈中取得变量的值,而不是从私有数据栈中取得变量的值。
使用volatile关键字增加了实例变量在多个线程之间的可见性,但是volatile不支持原子性。
volatile VS synchronized
下面将关键字volatile和synchronized进行一下比较:
volatile是线程同步的轻量级实现,所以volatile性能比synchronized要好,并且volatile只能修饰变量,而synchronized可以修饰方法以及代码块。 多线程访问volatile不会发生阻塞,而synchronized会出现阻塞。 volatile可以保证数据的可见性,但是不能保证原子性。
ok,java多线程中关于对象和变量的并发访问就到这里了。希望大家喜欢。

我要回帖

更多关于 linux关闭java线程 的文章

 

随机推荐