方法区和堆区的代码是多个线程共享的,多个线程同时操作方法区或堆区的共享代码时就会存在线程安全问题。
那怎么解决线程安全问题?
使用synchronized给共享资源加锁就是其中的一种解决方法。
简单使用
下面的代码中SynchronizedTest类的静态成员变量num存储在内存中的方法区,当被多线程同时操作时是线程不安全的
class SynchronizedTest {
private static int num = 0;
static class AThread implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
//休眠100毫秒来模拟实际开发情况
Thread.sleep(100);
num ++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
static class BThread implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(100);
num ++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws InterruptedException {
//创建线程并启动线程执行任务
Thread aThread = new Thread(new SynchronizedTest.AThread());
Thread bThread = new Thread(new SynchronizedTest.BThread());
aThread.start();
bThread.start();
//main线程等待aThread和bThread线程执行完毕
aThread.join();
bThread.join();
System.out.println(num); //小于20,存在线程安全问题
}
}
通过synchronized加锁解决线程安全问题
class SynchronizedTest {
private static int num = 0;
static class AThread implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
synchronized (SynchronizedTest.class){
Thread.sleep(100);
num ++;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
static class BThread implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
synchronized (SynchronizedTest.class){
Thread.sleep(100);
num ++;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws InterruptedException {
//创建线程并启动线程执行任务
Thread aThread = new Thread(new AThread());
Thread bThread = new Thread(new BThread());
aThread.start();
bThread.start();
//main线程等待aThread和bThread线程执行完毕
aThread.join();
bThread.join();
System.out.println(num); //等于20,不存在线程安全问题
}
}
锁的粒度
锁住当前对象
synchronized加在对象方法上或synchronized (this)代码块,锁的粒度都是当前对象,对象之间不互斥,当类的多个对象并发调用此方法,存在线程安全问题
class SynchronizedObject {
public static int num = 0;
//锁定的是对象
public synchronized void increNum1(){
try {
Thread.sleep(100);
num ++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void increNum2(){
//锁定的是对象
synchronized (this){
try {
Thread.sleep(100);
num ++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class SynchronizedObjectTest1 {
static class AThread implements Runnable {
private SynchronizedObject synchronizedObject = new SynchronizedObject();
@Override
public void run() {
for (int i = 0; i < 10; i++) {
//synchronizedObject.increNum1();
synchronizedObject.increNum2();
}
}
}
static class BThread implements Runnable {
private SynchronizedObject synchronizedObject = new SynchronizedObject();
@Override
public void run() {
for (int i = 0; i < 10; i++) {
//synchronizedObject.increNum1();
synchronizedObject.increNum2();
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread aThread = new Thread(new AThread());
Thread bThread = new Thread(new BThread());
aThread.start();
bThread.start();
aThread.join();
bThread.join();
System.out.println(SynchronizedObject.num); //小于20,线程不安全
}
}
class SynchronizedObjectTest2 {
static class AThread implements Runnable {
private SynchronizedObject synchronizedObject;
public AThread(SynchronizedObject synchronizedObject) {
this.synchronizedObject = synchronizedObject;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
//synchronizedObject.increNum1();
synchronizedObject.increNum2();
}
}
}
static class BThread implements Runnable {
private SynchronizedObject synchronizedObject;
public BThread(SynchronizedObject synchronizedObject) {
this.synchronizedObject = synchronizedObject;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
//synchronizedObject.increNum1();
synchronizedObject.increNum2();
}
}
}
public static void main(String[] args) throws InterruptedException {
SynchronizedObject synchronizedObject = new SynchronizedObject();
Thread aThread = new Thread(new AThread(synchronizedObject));
Thread bThread = new Thread(new BThread(synchronizedObject));
aThread.start();
bThread.start();
aThread.join();
bThread.join();
System.out.println(SynchronizedObject.num); //输出20,线程安全
}
}
锁住类的全部对象
synchronized加在类方法上或synchronized (SynchronizedClass.class)代码块,锁住类的全部对象,对象之间互斥,当类多个对象并发调用此方法,需要排队,不存在线程安全问题
class SynchronizedClass {
public static int num = 0;
public static void increNum1(){
try {
Thread.sleep(100);
num ++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void increNum2(){
synchronized (SynchronizedClass.class){
try {
Thread.sleep(100);
num ++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class SynchronizedClassTest1 {
static class AThread implements Runnable {
private SynchronizedClass synchronizedClass = new SynchronizedClass();
@Override
public void run() {
for (int i = 0; i < 10; i++) {
//synchronizedClass.increNum1();
synchronizedClass.increNum2();
}
}
}
static class BThread implements Runnable {
private SynchronizedClass synchronizedClass = new SynchronizedClass();
@Override
public void run() {
for (int i = 0; i < 10; i++) {
//synchronizedClass.increNum1();
synchronizedClass.increNum2();
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread aThread = new Thread(new AThread());
Thread bThread = new Thread(new BThread());
aThread.start();
bThread.start();
aThread.join();
bThread.join();
System.out.println(SynchronizedClass.num); //输出20,线程安全
}
}
class SynchronizedClassTest2 {
static class AThread implements Runnable {
private SynchronizedClass synchronizedClass;
public AThread(SynchronizedClass synchronizedClass) {
this.synchronizedClass = synchronizedClass;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
//synchronizedClass.increNum1();
synchronizedClass.increNum2();
}
}
}
static class BThread implements Runnable {
private SynchronizedClass synchronizedClass;
public BThread(SynchronizedClass synchronizedClass) {
this.synchronizedClass = synchronizedClass;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
//synchronizedClass.increNum1();
synchronizedClass.increNum2();
}
}
}
public static void main(String[] args) throws InterruptedException {
SynchronizedClass synchronizedClass = new SynchronizedClass();
Thread aThread = new Thread(new AThread(synchronizedClass));
Thread bThread = new Thread(new BThread(synchronizedClass));
aThread.start();
bThread.start();
aThread.join();
bThread.join();
System.out.println(SynchronizedClass.num); //输出20,线程安全
}
}
wait、notify和notifyAll
Object.wait()使当前的线程进入到等待状态(进入到等待队列)
Object.notifyAll() 唤醒等待中的全部线程
Object.notify() 随机唤醒一个线程
使用wait和notifyAll实现生产者消费者模式
/*
* 生产者
*/
class Producer extends Thread {
private List<String> container;
private int count = 1;
public Producer(String name, List<String> container) {
super(name);
this.container = container;
}
@Override
public void run() {
while (true) {
synchronized (container) {
if (container.size() == 10){
try {
//满了,不再生产,进入等待状态
container.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
else {
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("生产: 苹果"+count);
container.add(new String("苹果"+count));
count ++;
container.notifyAll();
}
}
}
}
}
/*
* 消费者
*/
class Consumer extends Thread {
private List<String> container;
public Consumer(String name, List<String> container) {
super(name);
this.container = container;
}
@Override
public void run() {
while (true) {
synchronized (container) {
if (container.isEmpty()){
try {
//没有产品可消费,进入等待状态
container.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
else {
try {
sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
String str = container.get(0);
container.remove(0);
System.out.println("消费: "+str);
container.notifyAll();
}
}
}
}
}
class Test {
public static void main(String[] args) {
List<String> container = new ArrayList<>();
new Producer("富士康", container).start();
new Consumer("专卖店", container).start();
}
}