当多个线程同时请求一个数据的时候,会导致数据不准确的情况。相互之间产生影响,容易出现线程安全的问题。比如多个线程操作同一个数据,都打算修改商品库存。
线程的同步真实的意思: 其实就是让你"排队",几个线程之间要排队。一个一个对共享资源进行操作。等一个结束以后,另外一个再进来操作,而不是同时进行操作。确保变量 是唯一的、准确的。
那么怎么实现线程同步呢
可以加锁
1.一个售票案例
package com.qf.c_Lock;
class SaleTicket implements Runnable{
private int ticket = 100;
@Override
public void run() {
while(true){
if(ticket>0){
System.out.println(Thread.currentThread().getName()+"卖出了第"+ticket+"张票");
ticket--;
}else{
System.out.println("卖完啦");
break;
}
}
}
}
public class Demo1 {
public static void main(String[] args) {
//强调的是:多个线程操作同一个数据 ticket
SaleTicket saleTicket = new SaleTicket();
new Thread(saleTicket,"线程一").start();
new Thread(saleTicket,"线程二").start();
}
}
两个线程都可以对ticket进行操作,售票,但是出现了问题,两个线程都不能即时更新已经被对方修改过的共享资源,线程是不安全的
试着去解决
2.同步方法
方案一:同步方法
public synchronized void eat(){
//synchronized修饰方法,锁方法
}
package com.qf.c_Lock;
class SaleTicket implements Runnable{
private int ticket = 100;
@Override
public synchronized void run() {
while(true){
if(ticket>0){
System.out.println(Thread.currentThread().getName()+"卖出了第"+ticket+"张票");
ticket--;
}else{
System.out.println("卖完啦");
break;
}
}
}
}
public class Demo1 {
public static void main(String[] args) {
//强调的是:多个线程操作同一个数据 ticket
SaleTicket saleTicket = new SaleTicket();
new Thread(saleTicket,"线程一").start();
new Thread(saleTicket,"线程二").start();
}
}
使用synchronized修饰run()方法,结果发现太极端:
一旦某一个线程抢先执行,它自己就把票卖完了,别的线程等不到资源
3.同步代码块
方案二:同步代码块
synchronized(this){
}
将一段代码放到{}中,然后用synchronized修饰,就会对这段代码上锁
package com.qf.c_Lock;
class SaleTicket implements Runnable{
private int ticket = 100;
@Override
public void run() {
while(true){
synchronized (this){
if(ticket>0){
System.out.println(Thread.currentThread().getName()+"卖出了第"+ticket+"张票");
ticket--;
}else{
System.out.println("卖完啦");
break;
}
}
}
}
}
public class Demo1 {
public static void main(String[] args) {
//强调的是:多个线程操作同一个数据 ticket
SaleTicket saleTicket = new SaleTicket();
new Thread(saleTicket,"线程一").start();
new Thread(saleTicket,"线程二").start();
}
}
这次将锁加到买票的核心代码if-else语句上,既可以实现线程同步(线程排队),又不会锁的太极端。
那能不能不用同步代码块而采用同步方法实现线程同步的卖票呢?
当然可以
4.同步方法再尝试
package com.qf.c_Lock;
class SaleTicket implements Runnable{
private int ticket = 100;
@Override
public void run() {
while(true){
test();
if(ticket<=0){
System.out.println("票卖完啦");
break;//这里需要加break结束循环,否则会一直输出票卖完啦
}
}
}
public synchronized void test(){
if(ticket>0){
System.out.println(Thread.currentThread().getName()+"卖出了第"+ticket+"张票");
ticket--;
}
}
}
public class Demo1 {
public static void main(String[] args) {
//强调的是:多个线程操作同一个数据 ticket
SaleTicket saleTicket = new SaleTicket();
new Thread(saleTicket,"线程一").start();
new Thread(saleTicket,"线程二").start();
}
}
这里把卖票的核心代码单独拿出来放到一个自己声明的方法中用synchronized修饰,然后调用
5.Java中的锁
1.synchronized
被称为隐式锁,会自动释放,是一个非公平的锁
2.Lock
被称为显示锁,是一个接口,实现ReentrantLock
这两个锁都可以解决线程同步问题,但synchronized更加强大,更加粒度化,更加灵活。所以开发时一般用synchronized 。
以后还会有线程池。线程池也有锁,更高级。
Lock有两个重要的方法:
lock();
unlock();
//要成对使用
package com.qf.c_Lock;
import java.util.concurrent.locks.ReentrantLock;
class SaleTicket1 implements Runnable{
int ticket = 100;
ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while(true){
try{
lock.lock();
if(ticket>0){
System.out.println(Thread.currentThread().getName()+"卖了第"+ticket+"张票");
ticket--;
}else{
System.out.println("票卖完啦");
}
}catch (Exception e){
}finally {
lock.unlock();
}
}
}
}
public class Demo2 {
public static void main(String[] args) {
SaleTicket saleTicket = new SaleTicket();
Thread thread1 = new Thread(saleTicket,"线程一");
thread1.start();
Thread thread2 = new Thread(saleTicket,"线程二");
thread2.start();
}
}
6.守护线程【了解】
守护线程是用来守护非守护线程的。
package com.qf.c_Lock;
class MyThread8 implements Runnable{
@Override
public void run() {
for(int i =0; i<500;i++){
System.out.println("守护线程"+i);
}
}
}
public class Demo3 {
public static void main(String[] args) {
Thread thread = Thread.currentThread();//当前线程是main
System.out.println(thread.isDaemon());//false 非守护线程
Thread thread1 = new Thread(new MyThread8());
thread1.setDaemon(true);//将thread1设置为守护线程
thread1.start();
for(int i = 0;i<50; i++){
System.out.println("主线程:"+i);
}
}
}
当程序中只剩下守护线程时,哪怕守护线程没有执行完,代码也会自己结束。
完结,撒花~