java基础-如何实现线程安全?synchronized的使用
进程与线程的概念:
进程:操作系统运行的一个程序,CPU资源分配的最小单位
线程:进程的一个执行单元,CPU调度的最小单位
一个进程至少有一个线程,如果进程有多个线程,则它是多线程应用程序
java线程栈是相互独立的,每个线程都有自己的栈空间,共享堆区和方法区
主线程:JVM启动主线程,主线程运行main方法
用户线程:开启新的线程,也称子线程
守护线程:守护线程是为其他线程提供服务 的线程,不能独立运行,当JVM中只有守护线程时,JVM就会退出
垃圾回收器就是一个守护线程
Java线程调度方式
线程睡眠:Thread.sleep(long millis),使线程转换到阻塞状态,当睡眠结束后,就转为就绪状态
线程等待:Object.wait(),导致当前的线程等待,直到其他线程调用此对象的notify()或notifyAll()
线程唤醒:Object.notify()方法,唤醒在此对象上等待的单个线程。
线程让步:Thread.yield(),暂停当前正在执行的线程对象,把执行机会让给相同或更高优先级的线程
线程加入:join(),等待其他线程终止
线程同步
线程安全问题:当多个线程同时操作堆区或者方法区的某个数据时,可能会出现数据不一致的现象
java线程是相互独立的,每个线程都有自己的栈空间,共享堆区和方法区
创建线程代码例子:
public class ThreadDemo extends Thread {
public void run(){
for(int i=0;i<100;i++){
System.out.println("ThreadDemo"+i);
}
}
}
class Test04{
public static void main(String[] args) {
ThreadDemo t1 = new ThreadDemo();
t1.start();//启动新的线程 自动执行run()方法
for(int i=1;i<10;i++){
System.out.println("main"+i);
}
}
/*
*在当前程序main 和 t1线程在同时执行,每次运行的结果可能不一样
* 多线程程序中的多个线程 谁抢到cpu谁执行
* */
}
如何解决线程安全问题:
1)每个线程都访问自己的局部遍历
2)如果多个线程必须操作 实例变量或者静态变量,可以采用线程同步技术。(当一个线程在操作期间,它不允许其他线程加入)
线程不安全例子:
public class BankAccount {
int balance = 10000;//账户余额:万元
public void withdraw(){
System.out.println(Thread.currentThread().getName()+"取钱前查询余额"+balance+"万元");
balance-=1000;//每次取1000万元
System.out.println(Thread.currentThread().getName()+"取了1000万后查询余额"+balance+"万元");
}
}
//用户操作
public class PersonThread extends Thread{
private BankAccount account;
public PersonThread(BankAccount account) {
super();
this.account = account;
}
@Override
public void run(){
//从账户中取钱
account.withdraw();
}
}
class Test{
public static void main(String[] args) {
//先开户
BankAccount account = new BankAccount();
//创建3个线程 模拟用户取钱
PersonThread bingbing = new PersonThread(account);
PersonThread xiaoming = new PersonThread(account);
PersonThread xiaogang = new PersonThread(account);
bingbing.setName("bingbing");
xiaoming.setName("xiaoming");
xiaogang.setName("xiaogang");
bingbing.start();
xiaoming.start();
xiaogang.start();
}
}
运行结果:

可以看出xiaoming取钱前查询余额10000万元 xiaoming取了1000万后查询余额8000万元
期间有其他线程操作了取的钱导致数据不一致
线程同步技术,解决线程不安全问题
工作原理:
1)任意对象都可作为锁对象,每个对象只有一个内置锁
2)某一时刻,1个锁对象最多只能被一个线程持有
3)如果线程获得了锁对象后会一直持有,直到执行完同步代码块后才释放
4)线程要执行同步代码块,必须持有锁对象
代码例子(多个线程必须操作 实例变量或者静态变量)
//线程安全例子
//1)bingbing先获得CPU执行权,执行withdraw方法,获得OBJ这个锁对象,执行取钱操作
//2)xiaoming获得CPU执行权,执行withdraw方法,在执行取钱操作需要获得锁对象,现在锁对象被bingbing持有,xiaoming转到等待锁对象池中进行阻塞
//3)xiaogang获得CPU执行权,执行withdraw方法,在执行取钱操作需要获得锁对象,现在锁对象被bingbing持有,xiaogang转到等待锁对象池中进行阻塞
//4)xiaogang重新获得CPU执行权,执行完取钱操作释放锁对象
//5)等待锁对象池中的 xiaoming或xiaogang中的1个获得锁对象,获得锁对象的 进入就绪状态,未获得锁对象的还是阻塞状态
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;//每次取1000万元
System.out.println(Thread.currentThread().getName()+"取了1000万后查询余额"+balance+"万元");
}
}
}
public class PersonThread extends Thread{
private BankAccount account;
public PersonThread(BankAccount account) {
super();
this.account = account;
}
@Override
public void run(){
//从账户中取钱
account.withdraw();
}
}
class Test{
public static void main(String[] args) {
//先开户
BankAccount account = new BankAccount();
//创建3个线程 模拟用户取钱
PersonThread bingbing = new PersonThread(account);
PersonThread xiaoming = new PersonThread(account);
PersonThread xiaogang = new PersonThread(account);
bingbing.setName("bingbing");
xiaoming.setName("xiaoming");
xiaogang.setName("xiaogang");
bingbing.start();
xiaoming.start();
xiaogang.start();
}
}
运行结果:

如何同步方法?保证方法顺序执行
public class MainSynchronized {
public static void main(String[] args) {
MainSynchronized mainSynchronized = new MainSynchronized();
new Thread(new Runnable() {
@Override
public void run() {
mainSynchronized.m1();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
mainSynchronized.m2();
}
}).start();
}
public synchronized void m1(){
System.out.println("m1方法开始执行");
for(int i=0;i<50;i++){
System.out.println("m1---"+i);
}
}
public synchronized void m2(){
System.out.println("m2方法开始执行");
for(int i=0;i<20;i++){
System.out.println("m2---"+i);
}
}
}

浙公网安备 33010602011771号