Java多线程 synchronized关键字

1、在Java多线程中,没用使用synchronized关键字:
// 业务类
class Example {
    // threadName 线程名称
    public void executeOne(String threadName) {
        for (int i = 0; i < 10; ++i) {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(threadName + ": " + i);
        }
    }
}

// 控制类
class ThreadOne extends Thread {
    private Example example;
    private String threadName; // 线程名称。在多线程时以示区别
	
    public ThreadOne(Example example, String threadName) {
        this.example = example;
        this.threadName = threadName;
    }
    public void run() {
	this.example.executeOne(this.threadName);
    }
}

// 测试类
public class ThradTest {
    public static void main(String[] args) {
	Example one = new Example();
        Thread t1 = new ThreadOne(one,"One");
        Thread t2 = new ThreadOne(one,"Two");

        t1.start();
        t2.start();
    }
}

在多线程中没有使用synchronized关键字时,两个线程同时执行executeOne,执行结果是没有先后顺序,也无法预知结果。某一次执行结果为:

Two: 0
One: 0
One: 1
Two: 1
One: 2
Two: 2
One: 3
Two: 3
Two: 4
One: 4
One: 5
Two: 5
One: 6
Two: 6
Two: 7
One: 7
One: 8
Two: 8
One: 9
Two: 9


2、在Java多线程中,使用synchronized关键字,且多线程操作同一对象:

只对业务类进行修改,也就是在executeOne方法名前添加关键字synchronized。修改结果如下:

// 业务类
class Example {
    // threadName 线程名称
    public synchronized void executeOne(String threadName) {
        for (int i = 0; i < 10; ++i) {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(threadName + ": " + i);
        }
    }
}
在多线程中使用synchronized关键字,两个线程按先后顺序执行 executeOne方法,结果有先后顺序,是可预知的结果。运行结果如下:

One: 0
One: 1
One: 2
One: 3
One: 4
One: 5
One: 6
One: 7
One: 8
One: 9
Two: 0
Two: 1
Two: 2
Two: 3
Two: 4
Two: 5
Two: 6
Two: 7
Two: 8
Two: 9

执行结果为什么有先后顺序呢?是因为使用synchronized关键字修饰executeOne方法。在第一个线程t1执行时,给业务类对象one加上了锁。第二个线程t2在t1线程未执行完成时,处于等待状态,也就不能执行one对象中的executeOne方法。待t1线程执行完毕,并释放了锁,t2线程就可以执行one对象中的executeOne方法。

3、第1、2点中,多线程都是处理同一个one对象,接下来使用多线程处理不同对象。在第2点java代码的基础上修改测试类代码。修改结果如下:

// 测试类
public class ThradTest {
    public static void main(String[] args) {
        Example one = new Example();
	Example two = new Example();
        Thread t1 = new ThreadOne(one,"One");
        Thread t2 = new ThreadOne(two,"Two");

        t1.start();
        t2.start();
    }
}
运行结果如下:

One: 0
Two: 0
One: 1
Two: 1
Two: 2
One: 2
Two: 3
One: 3
Two: 4
One: 4

One: 5
Two: 5
One: 6
Two: 6
Two: 7
One: 7

One: 8
Two: 8
Two: 9
One: 9

执行结果与第1点相似,也是没有顺序。原因:t1线程在执行操作时,给one对象加上锁,而t2线程执行时,是对two对象执行操作,不是对one对象操作。也就是两个线程处理不同的对象,执行结果各不受影响。

4、在第3点的基础上,我们给业务类Example类中executeOne方法前添加static关键字,执行结果又有什么不同之处

// 业务类
class Example {
    // threadName 线程名称
    public synchronized static void executeOne(String threadName) {
	for (int i = 0; i < 10; ++i) {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(threadName + ": " + i);
        }
    }
}

执行结果如下:

One: 0
One: 1
One: 2
One: 3
One: 4
One: 5
One: 6
One: 7
One: 8
One: 9
Two: 0
Two: 1
Two: 2
Two: 3
Two: 4
Two: 5
Two: 6
Two: 7
Two: 8
Two: 9
执行结果是有顺序,可预知的。原因是业务类Example的executeOne方法添加了static修饰,该方法不再属于对象(不属于one、two对象),而是属于类(Example)。t1线程在执行executeOne方法时,不在是给one对象加锁,而是给Class类(Example类)加锁,因此t2线程在t1线程释放锁之前处于等待状态

5、多个线程(ThreadOne、ThreadTwo)执行同一业务类(Example)不同方法(该方法用synchronized修饰),且多线程处理的是同一对象

// 业务类
class Example {
    // threadName 线程名称
    public synchronized void executeOne(String threadName) {
	for (int i = 0; i < 10; ++i) {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(threadName + ": " + i);
        }
    }
    public synchronized void executeTwo(String threadName) {
	for (int i = 0; i < 10; ++i) {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(threadName + ": " + i);
        }
    } 
}

// 控制类
class ThreadOne extends Thread {
    private Example example;
    private String threadName; // 线程名称。在多线程时以示区别
	
    public ThreadOne(Example example, String threadName) {
	this.example = example;
	this.threadName = threadName;
    }
    public void run() {
	this.example.executeOne(this.threadName);
    }
}
class ThreadTwo extends Thread {
    private Example example;
    private String threadName; // 线程名称。在多线程时以示区别
	
    public ThreadTwo(Example example, String threadName) {
	this.example = example;
	this.threadName = threadName;
    }
    public void run() {
	this.example.executeTwo(this.threadName);
    }
}

// 测试类
public class ThradTest {
    public static void main(String[] args) {
        Example one = new Example();
        Thread t1 = new ThreadOne(one,"One");
        Thread t2 = new ThreadTwo(one,"Two");

        t1.start();
        t2.start();
    }
}
执行结果与第2点相同。原因:多线程执行操作的是同一个对象。t1线程执行操作时,会给one对象加锁,t2线程就不能操作one对象,t2线程也就处于等待状态,等待t1线程释放锁。

6、多个线程(ThreadOne、ThreadTwo)执行同一业务类(Example)不同方法(该方法用synchronized修饰),且多线程处理的是不同对象

修改第5点中的测试类即可,修改结果为:

// 测试类
public class ThradTest {
    public static void main(String[] args) {
	Example one = new Example();
	Example two = new Example();
        Thread t1 = new ThreadOne(one,"One");
        Thread t2 = new ThreadTwo(two,"Two");

        t1.start();
        t2.start();
    }
}
执行结果与第3点类似。原因:t1线程执行操作对象与t2线程操作对象不同。t1线程操作时,给one对象加锁,并非给two加锁。t2对象操作的是two对象


7、synchronized代码块

    1)代码块在非静态方法中

    // 业务类
    class Example {
        // threadName 线程名称
	public void executeOne(String threadName) {
	    synchronized (this) {
		for (int i = 0; i < 10; ++i) {
	            try {
	                Thread.sleep(500);
	            } catch (InterruptedException e) {
	                e.printStackTrace();
	            }
	            System.out.println(threadName + ": " + i);
	        }
	    }
	}
    }
    // 控制类
    class ThreadOne extends Thread {
	private Example example;
	private String threadName; // 线程名称。在多线程时以示区别
	
	public ThreadOne(Example example, String threadName) {
	    this.example = example;
	    this.threadName = threadName;
	}
	public void run() {
	    this.example.executeOne(this.threadName);
	}
    }

    // 测试类
    public class ThradTest {
	public static void main(String[] args) {
	    Example one = new Example();
            Thread t1 = new ThreadOne(one,"One");
            Thread t2 = new ThreadOne(one,"Two");

            t1.start();
            t2.start();
	}
    }
执行结果与第2点相同,原因也一样 。如果将测试类做修改,修改为多线程处理不同的对象,执行结果第3点相同,原因也一样。其中this可以用private Object obj = new Object();obj替换

 

    2)代码块在静态方法中

    // 业务类
    class Example {
        // threadName 线程名称
	public void executeOne(String threadName) {
	    synchronized (Example.class) {
		for (int i = 0; i < 10; ++i) {
	            try {
	                Thread.sleep(500);
	            } catch (InterruptedException e) {
	                e.printStackTrace();
	            }
	            System.out.println(threadName + ": " + i);
	        }
	    }
	}
    }
    // 控制类
    class ThreadOne extends Thread {
	private Example example;
	private String threadName; // 线程名称。在多线程时以示区别
	
	public ThreadOne(Example example, String threadName) {
	    this.example = example;
	    this.threadName = threadName;
	}
	public void run() {
	    this.example.executeOne(this.threadName);
	}
    }

    // 测试类
    public class ThradTest {
        public static void main(String[] args) {
	    Example one = new Example();
            Thread t1 = new ThreadOne(one,"One");
            Thread t2 = new ThreadOne(one,"Two");

            t1.start();
            t2.start();
	}
    }
    执行结果与第4点相同, synchronized代码块是在静态方法中,该方法不属于one对象,是属于类Example。t1线程执行时,对Example类加锁,t2线程处于等待状态,等待t1释放锁,再执行。 其中Example.class可以用private static Object obj = new Object();的obj替换




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值