1.synchronized同步锁的引入
/*
* 非线程安全
* */
//多个线程共同访问一个对象中的实例变量,则会出现"非线程安全"问题
class MyRunnable1 implements Runnable{
private int num = 10;
public void run() {
try {
if(num > 0) {
System.out.println(""+Thread.currentThread().getName()+"开始"+",num= "+num--);
Thread.sleep(1000);
System.out.println(""+Thread.currentThread().getName()+"结束");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}public class Test5_5{
public static void main(String[] args) {
MyRunnable1 myRunnable1 = new MyRunnable1();
Thread thread1 = new Thread(myRunnable1,"线程1");
Thread thread2 = new Thread(myRunnable1,"线程2");
thread1.start();
thread2.start();
}
}
上例说明两个线程同时访问一个没有同步的方法,如果两个线程同时操作业务对象中的实例变量,则会出现“线程不安全”问题。
由此我们引入synchronized关键字来实现同步问题:
在Java中使用synchronized关键字控制线程同步,控制synchronized代码段不被多个线程同时执行,synchronized即可以使用在方法上也可以使用在代码块中。
2. 对象锁
(1)synchronized方法(对当前对象进行加锁)
若我们对如上代码进行修改,在run()方法上加入synchronized关键字使其变为同步方法。
/*
* 同步方法
* */
class MyRunnable1 implements Runnable{
private int num = 10;
public void run() {
this.print();
}
public synchronized void print() {
if(this.num > 0) {
System.out.println(""+Thread.currentThread().getName()+"开始"+",num= "+num--);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(""+Thread.currentThread().getName()+"结束");
}
}
}public class Test5_5{
public static void main(String[] args) {
MyRunnable1 myRunnable1 = new MyRunnable1();
Thread thread1 = new Thread(myRunnable1,"线程1");
Thread thread2 = new Thread(myRunnable1,"线程2");
thread1.start();
thread2.start();
}
}
结论:若两个线程同时访问同一个对象中的同步方法时一定是线程安全的。
(2)synchronized代码块(对某一个对象进行加锁)
如果要使用同步代码块必须设置一个要锁定的对象,所以一般可以锁定当前对象:this.
/*
* 同步代码块
* */
class MyRunnable1 implements Runnable{
private int num = 10;
public void run() {
try {
synchronized (this) {
if(num > 0) {
System.out.println(""+Thread.currentThread().getName()+"开始"+",num= "+num--);
Thread.sleep(1000);
System.out.println(""+Thread.currentThread().getName()+"结束");
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Test5_5{
public static void main(String[] args) {
MyRunnable1 myRunnable1 = new MyRunnable1();
Thread thread1 = new Thread(myRunnable1,"线程1");
Thread thread2 = new Thread(myRunnable1,"线程2");
thread1.start();
thread2.start();
}
}
(3)synchronized锁多对象
/*
* synchronized锁多对象
* */
class Sync{
public synchronized void print() {
System.out.println("print方法开始:"+Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("print方法结束"+Thread.currentThread().getName());
}
}
class MyThread extends Thread{
public void run() {
Sync sync = new Sync();
sync.print();
}
}
public class Test5_5{
public static void main(String[] args) {
for(int i = 0; i < 3;i++) {
Thread thread = new MyThread();
thread.start();
}
}
}
根据上例我们可以发现当synchronized锁多个对象时不能实现同步操作,由此可以得出关键字synchronized取得的锁都是对象锁,而不是将一段代码或者方法(函数)当作锁。哪个线程先执行带synchronized关键字的方法或synchronized代码块,哪个线程就有该方法或该代码块所持有的锁,其他线程只能呈现等待状态,前提是多个线程访问同一个对象。
只有共享资源的读写需要同步化,如果不是共享资源,那么就不需要同步化操作。
3.全局锁
实现全局锁有两种方式:
(1) 将synchronized关键字用在static方法上
synchronized加到static静态方法上是对Class类上锁,而synchronized加到非static方法上是给对对象上锁。Class锁可以对类的所有对象实例起作用。
/*
* synchronized用在static方法上
* */
class Sync{
static public synchronized void print() {
System.out.println("print方法开始:"+Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("print方法结束"+Thread.currentThread().getName());
}
}
class MyThread extends Thread{
public void run() {
Sync.print();
}
}
public class Test5_5{
public static void main(String[] args) {
for(int i = 0; i < 3;i++) {
Thread thread = new MyThread();
thread.start();
}
}
}
(2) 用synchronized对类的Class对象进行上锁
synchronized(class)代码块的作用与synchronized static方法的作用一样。
/*
* synchronized对类的Class对象上锁
* */
class Sync{
public void print() {
synchronized (Sync.class) {
System.out.println("print方法开始:"+Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("print方法结束"+Thread.currentThread().getName());
}
}
}
class MyThread extends Thread{
public void run() {
Sync sync = new Sync();
sync.print();
}
}
public class Test5_5{
public static void main(String[] args) {
for(int i = 0; i < 3;i++) {
Thread thread = new MyThread();
thread.start();
}
}
}