赞
踩
线程安全问题
在多线程程序中,当多个线程同时操作堆区/方法区同一个数据时,可能引发数据不一致的现象, 称为线程安全问题。
出现线程安全问题, 怎么办?
让每个线程都访问自己的局部变量, 不会产生线程安全问题
如果多个线程必须同时操作堆区/方法区同一个数据 , 采用线程同步技术
线程如何同步?
语法:
synchronized ( 锁对象 ) {
同步代码块
}
工作原理:
● 线程要执行同步代码块,必须先获得锁对象
● 任意对象都可以作为锁对象, 任意对象都有一个内置锁
● 一个锁对象最多被一个线程持有
● 线程持有了锁对象后,会一直持有, 直到执行完同步代码块后才会释放锁对象
package com.wkcto.chapter07.sync.p2;
/**
*/
public class BankAccount {
int balance = 10000 ; //余额 ,单位:万元
private static final Object OBJ = new Object(); //常量
//取钱的操作, 约定, 每次取钱1000 public void withdraw() { synchronized ( OBJ ) { //一般使用常量作为锁对象 System.out.println(Thread.currentThread().getName() + "取钱 前, 余额为:" + balance); balance -= 1000; System.out.println(Thread.currentThread().getName() + "取了1000万后, 余额为:" + balance); } /* * 1) xiaoming获得了CPU执行权, 执行withdraw()方法, 先获得OBJ锁对象, 执行同步代码块 * 2) xiaoming在执行同步代码块期间, CPU执行权被baby抢走了, xiaoming转为就绪状态 * babay获得CPU执行权, 要也执行同步代码块, 必须先获得OBJ锁对象, * 现在OBJ锁对象被xiaoming持有, baby线程转到等待锁对象池中阻塞 * 3) xiaoming重新获得CPU执行权, 继续执行同步代码块, 执行完同步代码块后, 释放OBJ锁对象 * 4) 等待锁对象池中的baby如果获得了锁对象, 转为就绪状态 */ }
}
package com.wkcto.chapter07.sync.p2;
/**
*/
public class PersonThread extends Thread {
private BankAccount bankaccount; //银行帐户
public PersonThread(BankAccount bankaccount) {
super();
this.bankaccount = bankaccount;
}
@Override
public void run() {
bankaccount.withdraw();
}
}
package com.wkcto.chapter07.sync.p2;
/**
*/
public class Test01 {
public static void main(String[] args) { //先开户 BankAccount account = new BankAccount(); //定义三个线程模拟三个人, 是从同一个帐户中取钱 PersonThread xiaoming = new PersonThread(account); PersonThread bingbing = new PersonThread(account); PersonThread baby = new PersonThread(account); xiaoming.setName("xiaoming"); bingbing.setName("bingbing"); baby.setName("baby"); xiaoming.start(); bingbing.start(); baby.start(); }
}
同步代码块
同步代码块要想实现同步,必须保证使用同一个锁对象
只要使用了同一个锁对象的同步代码块就可以同步
package com.wkcto.chapter07.sync.p3;
/**
*/
public class Test01 {
public static void main(String[] args) {
PrintNum pNum = new PrintNum();
//创建线程,调用m1()
new Thread(new Runnable() {
@Override
public void run() {
pNum.m1();
}
}).start();
//创建线程,调用m2()
new Thread(new Runnable() {
@Override
public void run() {
// pNum.m2(); //当使用this对象作为锁对象时, 可以同步
new PrintNum().m2(); //使用this作为锁对象, 不能同步, 与第一个线程的锁对象不是一个
}
}).start();
}
}
package com.wkcto.chapter07.sync.p3;
/**
*/
public class PrintNum {
private static final Object OBJ = new Object(); //定义常量
public void m1() {
// synchronized (OBJ) { //经常使用常量作为锁对象
synchronized ( this ) { //有时也会使用this作为锁对象 , 就是调用m1()方法的对象
for(int i = 1; i<=200; i++){
System.out.println(“wkcto is NB website”);
}
}
}
public void m2() {
// synchronized (OBJ) {
synchronized (this) {
for(int i = 1; i<=200; i++){
System.out.println(“bjpowernode is a good school”);
}
}
}
}
ackage com.wkcto.chapter07.sync.p4;
/**
*/
public class Test02 {
public static void main(String[] args) { //创建线程, 打印wkcto new Thread(new Runnable() { @Override public void run() { while( true ){ printText("wkcto"); } } }).start(); //创建线程, 打印bjpowernode new Thread(new Runnable() { @Override public void run() { while( true ){ printText("bjpowernode"); } } }).start(); } private static final Object OBJ = new Object(); //常量 //静态方法,打印一个字符串 public static void printText( String text) {
// synchronized (OBJ) {
synchronized ( Test02.class ) { //使用当前类的运行时类对象作为锁对象, 有人把它称为类锁
//可以简单的理解 为把当前类的字节码文件作为锁对象
for( int i = 0 ; i<text.length() ; i++){
System.out.print( text.charAt(i));
}
System.out.println();
}
}
}
同步方法
package com.wkcto.chapter07.sync.p5;
/**
同步实例方法, 就是把整个方法体作为同步代码块, 默认锁对象 是this对象
*/
public class Test01 {
public static void main(String[] args) {
Test01 obj = new Test01();
//创建线程, 调用m1()
new Thread(new Runnable() {
@Override
public void run() {
obj.m1();
}
}).start();
//创建线程, 调用m2()
new Thread(new Runnable() {
@Override
public void run() {
obj.m2();
}
}).start();
}
/*
public void m2() {
synchronized ( this ) {
for(int i =1; i<=500; i++){
System.out.println( Thread.currentThread().getName() + “======>” + i);
}
}
}
}
package com.wkcto.chapter07.sync.p5;
/**
同步静态方法, 就是把整个方法体作为同步代码块, 默认锁对象 是当前类的运行时类对象
*/
public class Test02 {
public static void main(String[] args) {
//创建线程, 调用m1()
new Thread(new Runnable() {
@Override
public void run() {
Test02.m1();
}
}).start();
//创建线程, 调用m2()
new Thread(new Runnable() {
@Override
public void run() {
Test02.m2();
}
}).start();
}
/*
public static void m2() {
synchronized ( Test02.class ) {
for(int i =1; i<=500; i++){
System.out.println( Thread.currentThread().getName() + “======>” + i);
}
}
}
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。