Java高并发程序-Chapter2 Java并行程序基础 (第八讲)线程组 、守护线程、线程优先级
2018-03-27 11:38
706 查看
线程安全的概念与 synchronized
1. 指定加锁对象
指定加锁对象:对给定对象加锁,进入同步代码前要获得给定对象的锁
public class AccountSyncByInstance implements Runnable {
public void run() {
for (int j = 0; j < 100000; j++) {
synchronized (this) {
i++;
}
}
}
public int getSummary() {
return i;
}
private int i = 0;
public static void main(String[] args) throws InterruptedException {
AccountSyncByInstance instance = new AccountSyncByInstance();
Thread t1 = new Thread(instance);
Thread t2 = new Thread(instance);
Thread t3 = new Thread(instance);
t1.start();
t2.start();
t3.start();
t1.join();
t2.join();
t3.join();
System.out.println(instance.getSummary());
}
}
2. 直接作用于实例方法
相当于对当前实例加锁,进入同步代码前要获得当前实例的锁
public class AccountSyncByMethod implements Runnable {
public void run() {
for (int j = 0; j < 100000; j++) {
synchronized (this) {
increase();
}
}
}
private synchronized void increase() {
i++;
}
public int getSummary() {
return i;
}
private int i = 0;
public static void main(String[] args) throws InterruptedException {
AccountSyncByMethod instance = new AccountSyncByMethod();
Thread t1 = new Thread(instance);
Thread t2 = new Thread(instance);
Thread t3 = new Thread(instance);
t1.start();
t2.start();
t3.start();
t1.join();
t2.join();
t3.join();
System.out.println(instance.getSummary());
}
}
3. 直接作用于静态方法
直接作用于静态方法:相当于对当前类加锁,进入同步代码前要获得当前类的锁
一种错误的同步方式如下:
public class AccountSyncByBad implements Runnable {
public void run() {
for (int j = 0; j < 100000; j++) {
synchronized (this) {
increase();
}
}
}
private synchronized void increase() {
i++;
}
public int getSummary() {
return i;
}
private static int i = 0;
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new AccountSyncByBad());
Thread t2 = new Thread(new AccountSyncByBad());
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}
虽然在第3行的 Increase()方法中,申明这是一个同步方法。
但很不幸的是,执行这段代码的两个线程都指向了不同的 Runnable实例。
Thread t1 = new Thread(new AccountSyncByBad());
Thread t2 = new Thread(new AccountSyncByBad());由第13、14行可以看到,这两个线程的 Runnable实例并不是同一个对象。
因此,线程t1会在进入同步方法前加锁自己的 Runnable实例,而线程t2也关注于自己的对象锁。
换言之,这两个线程使用的是两把不同的锁。因此,线程安全是无法保证的。
但我们只要简单地修改上述代码,就能使其正确执行。
那就是使用 synchronized的第三种用法,将其作用于静态方法private static synchronized void increase() {
i++;
}除了用于线程同步、确保线程安全外, synchronized还可以保证线程间的可见性和有序性。
1. 指定加锁对象
指定加锁对象:对给定对象加锁,进入同步代码前要获得给定对象的锁
public class AccountSyncByInstance implements Runnable {
public void run() {
for (int j = 0; j < 100000; j++) {
synchronized (this) {
i++;
}
}
}
public int getSummary() {
return i;
}
private int i = 0;
public static void main(String[] args) throws InterruptedException {
AccountSyncByInstance instance = new AccountSyncByInstance();
Thread t1 = new Thread(instance);
Thread t2 = new Thread(instance);
Thread t3 = new Thread(instance);
t1.start();
t2.start();
t3.start();
t1.join();
t2.join();
t3.join();
System.out.println(instance.getSummary());
}
}
2. 直接作用于实例方法
相当于对当前实例加锁,进入同步代码前要获得当前实例的锁
public class AccountSyncByMethod implements Runnable {
public void run() {
for (int j = 0; j < 100000; j++) {
synchronized (this) {
increase();
}
}
}
private synchronized void increase() {
i++;
}
public int getSummary() {
return i;
}
private int i = 0;
public static void main(String[] args) throws InterruptedException {
AccountSyncByMethod instance = new AccountSyncByMethod();
Thread t1 = new Thread(instance);
Thread t2 = new Thread(instance);
Thread t3 = new Thread(instance);
t1.start();
t2.start();
t3.start();
t1.join();
t2.join();
t3.join();
System.out.println(instance.getSummary());
}
}
3. 直接作用于静态方法
直接作用于静态方法:相当于对当前类加锁,进入同步代码前要获得当前类的锁
一种错误的同步方式如下:
public class AccountSyncByBad implements Runnable {
public void run() {
for (int j = 0; j < 100000; j++) {
synchronized (this) {
increase();
}
}
}
private synchronized void increase() {
i++;
}
public int getSummary() {
return i;
}
private static int i = 0;
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new AccountSyncByBad());
Thread t2 = new Thread(new AccountSyncByBad());
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}
虽然在第3行的 Increase()方法中,申明这是一个同步方法。
但很不幸的是,执行这段代码的两个线程都指向了不同的 Runnable实例。
Thread t1 = new Thread(new AccountSyncByBad());
Thread t2 = new Thread(new AccountSyncByBad());由第13、14行可以看到,这两个线程的 Runnable实例并不是同一个对象。
因此,线程t1会在进入同步方法前加锁自己的 Runnable实例,而线程t2也关注于自己的对象锁。
换言之,这两个线程使用的是两把不同的锁。因此,线程安全是无法保证的。
但我们只要简单地修改上述代码,就能使其正确执行。
那就是使用 synchronized的第三种用法,将其作用于静态方法private static synchronized void increase() {
i++;
}除了用于线程同步、确保线程安全外, synchronized还可以保证线程间的可见性和有序性。
相关文章推荐
- Java高并发程序-Chapter2 Java并行程序基础 (第四讲)进程和线程
- Java高并发程序-Chapter2 Java并行程序基础 (第五讲)线程的基本操作
- Java基础——线程间的通信+生产者消费者程序+守护线程+Join方法+线程优先级
- Java高并发程序-Chapter2 Java并行程序基础 (第六讲)volatile 与 Java 内存模型 JMM
- Java并发编程之线程生命周期、守护线程、优先级、关闭和join、sleep、yield、interrupt
- java 多线程系列基础篇(十)之线程优先级和守护线程
- Java高并发设计——并行程序基础一
- Java_基础—设置休眠/守护/插队/礼让/优先级线程
- 【Java 语言】Java 多线程 一 ( 线程基础 : 线程启动 | 线程停止 | 线程暂停 | 线程优先级 | 守护线程)
- 黑马程序员_Java基础[28]_线程3、优先级、线程组
- java高并发程序设计总结二:java并行程序基础
- Java并发学习笔记(16)守护线程,线程组
- Java高并发程序设计笔记2之并行程序基础
- 并发基础(三) java线程优先级
- Java高并发设计——并行程序基础二
- Java多线程基础--10之 线程优先级和守护线程
- 【Java并发编程】之四:守护线程与线程阻塞的四种情况
- Java 多线程编程之一 进程与线程,并发和并行的区别
- 【Java并发编程】之四:守护线程与线程阻塞的四种情况
- java多线程并发(二)(线程基础)