多线程任务经常会出现数据不一致的情况,要解决这种问题,就需要使用synchronized同步锁。
目录
3.利用AtomicInteger的原子性,简化代码,不用加锁
一、synchronized的基础知识
1.概念
synchronized关键字,也可以理解为同步锁。synchronized就像是一把锁一样,把需要互斥的代码锁住,只有获得了这把锁的线程才可以访问这段代码。同时,只有一个线程可以获得这把锁,这样就实现了原子性,这段代码也称做为临界区。临界区就不会被随意访问了。
2. synchronized的使用方法
2.1 synchronized修饰实例方法
public synchronized void doSth1(){
System.out.println("实例方法加锁");
}
2.2 synchronized修饰静态方法
public synchronized static void doSth3(){
System.out.println("静态方法加锁");
}
2.3 synchronized修饰代码块
public void doSth2(){
synchronized (this){
System.out.println("在实例方法中的代码块加锁");
}
}
public static void doSth4(){
synchronized (Class.class){
System.out.println("在静态方法中的代码块加锁");
}
}
//直接使用synchronized关键字
synchronized (Counter.lock){
for (int i = 0; i <10000 ; i++) {
//临界区
Counter.count-=1;
}
}//释放锁
二、相关案例
1.多线程售票
代码如下:
package org.example;
public class ProjectExample {
public static void main(String[] args) {
TicketPool publicTicketPool=new TicketPool(20);
new Thread(publicTicketPool,"窗口1").start();
new Thread(publicTicketPool,"窗口2").start();
new Thread(publicTicketPool,"窗口3").start();
}
}
class TicketPool implements Runnable{
private int count;
public TicketPool(int count){
this.count=count;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"开始卖票");
synchronized (this){
while(true){
if(count<=0){
System.out.println("票售罄了,"+Thread.currentThread().getName()+"关闭");
break;
}else{
String name=Thread.currentThread().getName();
System.out.println(name+"售出票"+"还剩"+(--count)+"张票");
try {
//sleep()休眠期间不释放锁
//Thread.sleep(1000);
//wait()等待期间释放锁,必须要由充当锁的对象调用(必须在syncjronized代码块里面)
this.wait(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
}
}
2.多线程打印数字和字母
代码如下:
package org.example;
//输出12A 34B 56C 78D 910E
// 1112F 1314G 1516H 1718I 1920J 2122K 2324L
// 2526M 2728N 2930O 3132P 3334Q 3536R 3738S 3940T
// 4142U 4344V 4546W 4748X 4950Y 5152Z 格式内容
public class ProjectExample2 {
public static void main(String[] args) {
Object lock=new Object();
//分别创建两个线程,执行打印数字和字母的线程任务
Thread t1=new Thread(new Number(lock));
t1.start();
Thread t2=new Thread(new Character(lock));
t2.start();
}
}
//数字线程任务
class Number implements Runnable{
public Object lock;
public Number(Object lock) {
this.lock=lock;
}
@Override
public void run() {
//加同步锁,使得输出的时候不会被打断
synchronized (lock){
for (int i = 1; i <=52 ; i++) {
//奇数前面加入空格
if ((i&1)==1){
//第一个数字前没有空格
if (i!=1){
System.out.print(" ");
}
}
//打印数字
System.out.print(i);
//偶数进入等待,等待字母进程,在等待前唤醒字母进程
if ((i&1)==0){
//【数字进程】唤醒【字母进程】
lock.notifyAll();
try {
//【数字进程】等待,并释放锁
lock.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
}
}
//字母线程任务
class Character implements Runnable{
public Object lock;
public Character(Object lock) {
this.lock=lock;
}
@Override
public void run() {
synchronized (lock){
for (char c ='A' ; c <='Z' ; c++) {
System.out.print(c);
//字母进程唤醒数字进程
lock.notifyAll();
if(c<'Z'){
try {
//小于Z,字母线程等待,并释放锁
lock.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
}
}
3.利用AtomicInteger的原子性,简化代码,不用加锁
代码如下:
package org.example;
import java.util.concurrent.atomic.AtomicInteger;
public class ProjectExample3 {
//利用AtomicInteger的原子性,简化代码,不用加锁
private static AtomicInteger counter=new AtomicInteger();
public static void main(String[] args) {
Thread t1=new Thread(()->{
for (int i = 0; i <=10000 ; i++) {
int value=counter.incrementAndGet();
System.out.println("本次递增的结果是:"+value);
}
});
Thread t2=new Thread(()->{
for (int i = 0; i <=10000 ; i++) {
int value=counter.decrementAndGet();
System.out.println("本次递减的结果是:"+value);
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("最后的结果为:"+counter);
}
}
多线程同步问题:synchronized与案例
174

被折叠的 条评论
为什么被折叠?



