4. 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。
package ThreadExample;
public class SynchExample implements Runnable{
private int count=0;
@Override
public void run() {
// TODO Auto-generated method stub
domore();
}
private void domore() {
// TODO Auto-generated method stub
synchronized(this)
{
for(int i=0;i<5;i++)
System.out.println(Thread.currentThread().getName()+":"+(count++));
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
SynchExample myrunnable=new SynchExample();
Thread thread1=new Thread(myrunnable,"Thread1");
Thread thread2=new Thread(myrunnable,"Thread2");
thread1.start();
thread2.start();
}
}
当两个并发线程(thread1和thread2)访问同一个对象(syncThread)中的synchronized代码块时,在同一时刻只能有一个线程得到执行,另一个线程受阻塞,必须等待当前线程执行完这个代码块以后才能执行该代码块。Thread1和thread2是互斥的,因为在执行synchronized代码块时会锁定当前的对象,只有执行完该代码块才能释放该对象锁,下一个线程才能执行并锁定该对象。
public static void main(String[] args) {
// TODO Auto-generated method stub
SynchExample myrunnable=new SynchExample();
SynchExample myrunnable1=new SynchExample();
Thread thread1=new Thread(myrunnable,"Thread1");
Thread thread2=new Thread(myrunnable1,"Thread2");
thread1.start();
thread2.start();
}
这是因为synchronized只锁定对象,每个对象只有一个锁(lock)与之相关联
这时创建了两个SyncThread的对象syncThread1和syncThread2,线程thread1执行的是syncThread1对象中的synchronized代码(run),而线程thread2执行的是syncThread2对象中的synchronized代码(run);我们知道synchronized锁定的是对象,这时会有两把锁分别锁定syncThread1对象和syncThread2对象,而这两把锁是互不干扰的,不形成互斥,所以两个线程可以同时执行。
package ThreadExample;
public class SynchExample implements Runnable{
private int count=0;
@Override
public void run() {
// TODO Auto-generated method stub
if(Thread.currentThread().getName()=="Thread1")
domore();
else
domore2();
}
private void domore() {
// TODO Auto-generated method stub
synchronized(this)
{
for(int i=0;i<5;i++)
System.out.println(Thread.currentThread().getName()+":"+(count++));
}
}
private void domore2() {
// TODO Auto-generated method stub
for(int i=0;i<5;i++)
System.out.println(Thread.currentThread().getName()+":"+(count++));
}
public static void main(String[] args) {
// TODO Auto-generated method stub
SynchExample myrunnable=new SynchExample();
SynchExample myrunnable1=new SynchExample();
Thread thread1=new Thread(myrunnable,"Thread1");
Thread thread2=new Thread(myrunnable1,"Thread2");
thread1.start();
thread2.start();
}
}
上面代码中countAdd是一个synchronized的,printCount是非synchronized的。从上面的结果中可以看出一个线程访问一个对象的synchronized代码块时,别的线程可以访问该对象的非synchronized代码块而不受阻塞。
当有一个明确的对象作为锁时,就可以用类似下面这样的方式写程序。
public void method3(SomeObject obj)
{
//obj 锁定的对象
synchronized(obj)
{
// todo
}
}
class Test implements Runnable
{
private byte[] lock = new byte[0]; // 特殊的instance变量
public void method()
{
synchronized(lock) {
// todo 同步代码块
}
}
public void run() {
}
}
public synchronized void method()
{
// todo
}
public void method()
{
synchronized(this) {
// todo
}
}
package ThreadExample;
public class SynchExample implements Runnable{
private static int count=0;
@Override
public void run() {
// TODO Auto-generated method stub
// if(Thread.currentThread().getName()=="Thread1")
domore();
// else
// domore2();
}
private synchronized static void domore() {
// TODO Auto-generated method stub
for(int i=0;i<5;i++)
System.out.println(Thread.currentThread().getName()+":"+(count++));
}
private void domore2() {
// TODO Auto-generated method stub
for(int i=0;i<5;i++)
System.out.println(Thread.currentThread().getName()+":"+(count++));
}
public static void main(String[] args) {
// TODO Auto-generated method stub
SynchExample myrunnable=new SynchExample();
SynchExample myrunnable1=new SynchExample();
Thread thread1=new Thread(myrunnable,"Thread1");
Thread thread2=new Thread(myrunnable1,"Thread2");
thread1.start();
thread2.start();
}
}
syncThread1和syncThread2是SyncThread的两个对象,但在thread1和thread2并发执行时却保持了线程同步。这是因为run中调用了静态方法method,而静态方法是属于类的,所以syncThread1和syncThread2相当于用了同一把锁。