1.将任何对象作为对象监视器,也就是以锁非this对象
class Service {
private String username;
private String anyString = new String();
public void setUsername(String username){
try{
synchronized (anyString){
System.out.println("线程:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"进入同步块");
this.username = username;
Thread.sleep(3000);
System.out.println("线程:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"离开同步块");
}
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
class ThreadA extends Thread{
private Service service;
public ThreadA(Service service){
this.service = service;
}
public void run(){
service.setUsername("a");
}
}
class ThreadB extends Thread{
private Service service;
public ThreadB(Service service){
this.service = service;
}
public void run(){
service.setUsername("b");
}
}
class Run{
public static void main(String[] args){
Service service = new Service();
ThreadA threadA = new ThreadA(service);
threadA.setName("A");
threadA.start();
ThreadB threadB = new ThreadB(service);
threadB.setName("B");
threadB.start();
}
}
可见,使用synchronized(非this对象)同步代码块进行同步操作时,对象监视器必须是相同的对象,如果不是同一个对象监视器,运行的结果就是异步调用。这里是对anyString对象进行监视,由于为实例变量,所以可以保证为同一个对象。
把上述注释的的代码放到鼠标位置,这时就可以知道anyString为一个占变量,显然每次不可能是同一个对象,所以这里的代码块不会同步运行
2.静态同步synchronized方法与synchronized(class)代码块
关键字synchronized因应用在static方法上,是表示给所有类对象实例加锁,并不像前面所讲的对象锁那样,只给一个对象加锁。
对象锁:多个线程想要同步效果,必须保证对象锁是给同一个对象
3.String常量池特性
class Service {
//由于常量池特性,两个线程都传相同参数,第二个和第一个其实是一样的
public void print(String stringParam){
try{
synchronized (stringParam){
while(true){
System.out.println(Thread.currentThread().getName());
Thread.sleep(1000);
}
}
}catch(InterruptedException e){
}
}
}
class ThreadA extends Thread{
private Service service;
public ThreadA(Service service){
this.service = service;
}
public void run(){
service.print("AA");
}
}
class ThreadB extends Thread{
private Service service;
public ThreadB(Service service){
this.service = service;
}
public void run(){
service.print("AA");
}
}
class Run{
public static void main(String[] args){
Service service = new Service();
ThreadA threadA = new ThreadA(service);
threadA.setName("A");
threadA.start();
ThreadB threadB = new ThreadB(service);
threadB.setName("B");
threadB.start();
}
}
因此在大多数情况下,同步synchronized代码块都不使用String作为锁对象,而改用其它
4.解决异步死循环
class RunThread extends Thread{
private boolean isRunning = true;
public boolean isRunning(){
return isRunning;
}
public void setRunning(boolean isRunning){
this.isRunning = isRunning;
}
public void run(){
System.out.println("进入了run");
while(isRunning == true){
}
System.out.println("线程被终止了");
}
}
public class Run {
public static void main(String[] args){
try{
RunThread thread = new RunThread();
thread.start();
Thread.sleep(1000);
thread.setRunning(false);
System.out.println("已经赋值false");
}catch(InterruptedException e){
}
}
}
这里会出现死循环,why?我不是已经给isRunning=false了吗?在启动RunThread线程时,private boolean isRunning=true保存在公共堆栈及线程私有堆栈中。在JVM被设置为-server模式时为了线程运行效率,线程一直在私有堆栈中取得isRunning的值true.而代码thread.setRunning(false)虽然被执行,更新的却是公共堆栈中的isRunning的值。
这里可以给变量加一个volatitle关键字,强制从公共内存中读取变量