先来看一段代码:
class MyThread implements Runnable{
private int count = 10;
@Override
public void run() {
while(count > 0) {
System.out.println(Thread.currentThread().getName() + "开始执行");
System.out.println("count还剩" + --count);
System.out.println(Thread.currentThread().getName() + "执行结束");
System.out.println();
}
}
}
public class Test{
public static void main(String[] args) {
MyThread myThread = new MyThread();
new Thread(myThread).start();
new Thread(myThread).start();
new Thread(myThread).start();
}
}
运行结果如下:
Thread-0开始执行
Thread-2开始执行
Thread-1开始执行
count还剩8
count还剩9
Thread-2执行结束
count还剩7
Thread-1执行结束
Thread-1开始执行
Thread-0执行结束
Thread-0开始执行
count还剩5
Thread-0执行结束
Thread-2开始执行
count还剩4
Thread-2执行结束
Thread-2开始执行
count还剩3
count还剩6
Thread-2执行结束
Thread-2开始执行
Thread-0开始执行
count还剩2
Thread-2执行结束
Thread-2开始执行
count还剩0
Thread-2执行结束
Thread-1执行结束
count还剩1
Thread-0执行结束
很显然这并不是我们想要的结果,我们想要的结果是:一个独自完整地按顺序跑完自己的run()方法,然而上面的结果是乱序的:上一个线程还没有跑完自己的任务,第二个线程就进来了。那么如何来解决这个问题呢?
首先我们来分析一下,三个线程同时拿到我们自己创建的对象myThread,然后启动这三个线程,这三个线程会同时进入这个run()方法进行执行。如果我们想要每一个线程进入后完整的跑完自己的任务,这时候就需要把这个myThread对象锁起来,不让其他线程拿到,这样就能实现。就比如说,有一个房间,你进入之后,不想要其他人再进来,你就得把门锁住一个道理。
在Java里面为我们提供了一个叫做“synchronized”的锁子。那么它应该怎样来使用呢?
“synchronized”的两种模式:同步方法、同步代码块。
一、对象锁:
1、同步代码块:在代码块前面加上synchronized(要锁的对象)。
class MyThread implements Runnable{
private int count = 10;
@Override
public void run() {
synchronized (this) {
while(count > 0) {
System.out.println(Thread.currentThread().getName() + "开始执行");
System.out.println("count还剩" + --count);
System.out.println(Thread.currentThread().getName() + "执行结束");
System.out.println();
}
}
}
}
public class Test{
public static void main(String[] args) {
MyThread myThread = new MyThread();
new Thread(myThread).start();
new Thread(myThread).start();
new Thread(myThread).start();
}
}
2、同步方法:在方法的返回值前面加上synchronized关键字。
class MyThread implements Runnable{
private int count = 10;
@Override
public void run() {
while(count > 0) {
count--;
fun();
}
}
public synchronized void fun() {
System.out.println(Thread.currentThread().getName() + "开始执行");
System.out.println("count还剩" + count);
System.out.println(Thread.currentThread().getName() + "执行结束");
System.out.println();
}
}
public class Test{
public static void main(String[] args) {
MyThread myThread = new MyThread();
new Thread(myThread).start();
new Thread(myThread).start();
new Thread(myThread).start();
}
}
二、全局锁:
在上面,我们锁住的都是myThread对象,如果要锁住多个对象的同一个方法又该怎么办呢?
这里与对象锁也有两种方法:同步方法和同步代码块。
1、同步代码块前的括号里写成想要锁住的方法的类.class
class MyThread implements Runnable{
private static int count = 10;
@Override
public void run() {
synchronized (MyThread.class) {
while(count > 0) {
count--;
fun();
}
}
}
public void fun() {
System.out.println(Thread.currentThread().getName() + "开始执行");
System.out.println("count还剩" + count);
System.out.println(Thread.currentThread().getName() + "执行结束");
System.out.println();
}
}
public class Test{
public static void main(String[] args) {
MyThread myThread = new MyThread();
new Thread(myThread).start();
new Thread(myThread).start();
new Thread(myThread).start();
}
}
2、在前面所说同步方法的基础上,加上static关键字,就可以实现全局锁。
class MyThread implements Runnable{
private static int count = 10;
@Override
public void run() {
while(count > 0) {
fun();
}
}
public synchronized static void fun() {
System.out.println(Thread.currentThread().getName() + "开始执行");
System.out.println("count还剩" + count);
System.out.println(Thread.currentThread().getName() + "执行结束");
System.out.println();
count--;
}
}
public class Test{
public static void main(String[] args) {
MyThread myThread = new MyThread();
new Thread(myThread).start();
new Thread(myThread).start();
new Thread(myThread).start();
}
}