说到并发还是来点基础入门
什么是并发问题?

我的理解是
当我们对程序里一个共享变量同时读和修改的时候就会产生并发问题
在数据库里
select 同时update 为什么不会产生并发问题?

实例程序,摘自:https://blog.csdn.net/tomcat_2014/article/details/60575942

package com.tl.skyLine.thread;
 
/**
 * Created by tl on 17/3/6.
 */
public class SellTicket {
 
    public static void main(String[] args) {
        TicketWindow tw = new TicketWindow();
        Thread t1 = new Thread(tw, \"一号窗口\");
        Thread t2 = new Thread(tw, \"二号窗口\");
        Thread t3 = new Thread(tw, \"三号窗口\");
        t1.start();
        t2.start();
        t3.start();
    }
}
 
class TicketWindow implements Runnable {
    private int tickets = 10;
 
    @Override
    public void run() {
        while (true) {
            if (tickets > 0) {
                System.out.println(\"还剩余票:\" + tickets + \"张\");
                tickets--;
                System.out.println(Thread.currentThread().getName() + \"卖出一张火车票,还剩\" + tickets + \"张\");
            } else {
                System.out.println(\"余票不足,暂停出售!\");
//                wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用
                try {
                    Thread.sleep(1000 * 60 * 5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

在这个过程中,因为ticket是共享变量,所以会发生线程问题

我们想着加锁,加锁有几个方向去加,第一是加在变量前,第二是加在方法前,第三是加在对象里(类级别)
产生了这几个关键字 volatile,ThreadLocal,synocize,Automic;
我们使用volatile关键字做了什么?
\"在这里插入图片描述\"
\"在这里插入图片描述\"

package test.blockchain.bean;

/**
 * Created by tl on 17/3/6.
 */
public class SellTicket {

	public static void main(String[] args) {
		TicketWindow tw = new TicketWindow();
		Thread t1 = new Thread(tw, \"一号窗口\");
		Thread t2 = new Thread(tw, \"二号窗口\");
		Thread t3 = new Thread(tw, \"三号窗口\");
		t1.start();
		t2.start();
		t3.start();
	}
}

class TicketWindow implements Runnable {
	private volatile int tickets = 100;

	@Override
	public void run() {
		while (true) {
			if (tickets > 0) {
				System.out.println(\"还剩余票:\" + tickets + \"张\");
				tickets = tickets - 1; //注意我还改了这个地方。
				System.out.println(Thread.currentThread().getName() + \"卖出一张火车票,还剩\" + tickets + \"张\");
			} else {
				System.out.println(\"余票不足,暂停出售!\");
				// wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用
				try {
					Thread.sleep(1000 * 60 * 5);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

摘自:https://blog.csdn.net/zbw18297786698/article/details/53420780

4.1使用volatile以后,做了如下事情

每次修改volatile变量都会同步到主存中。
每次读取volatile变量的值都强制从主存读取最新的值(强制JVM不可优化volatile变量,如JVM优化后变量读取会使用cpu缓存而不从主存中读取)

4.2 volatile解决的是多线程间共享变量的可见性问题,而保证不了多线程间共享变量原子性问题。对于多线程的i++,++i,依然还是会存在多线程问题,volatile是无法解决的.如下:使用一个线程i++,另一个i–,最终得到的结果不为0。
\"在这里插入图片描述\"

package test.blockchain.bean;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * Created by tl on 17/3/6.
 */
public class SellTicket {

	public static void main(String[] args) {
		TicketWindow tw = new TicketWindow();
		Thread t1 = new Thread(tw, \"一号窗口\");
		Thread t2 = new Thread(tw, \"二号窗口\");
		Thread t3 = new Thread(tw, \"三号窗口\");
		t1.start();
		t2.start();
		t3.start();
	}
}

class TicketWindow implements Runnable {
	private volatile int tickets = 1000;

	@Override
	public void run() {
		while (tickets > 0) {
			tickets = tickets-1;

			System.out.println(Thread.currentThread().getName() + \"卖出一张火车票,还剩\" + tickets + \"张\");

		}
	}
}

然而发现好像并没有什么用,为什么?因为我们保证了同时读最新的变量,但是我们无法控制程序里的写操作是否比读还要快,我们快速读了,然后进行两次+1后写入了主存,然后下次读的时候就变成了两次读

该用Automic类

public class SellTicket {

	public static void main(String[] args) {
		TicketWindow tw = new TicketWindow();
		Thread t1 = new Thread(tw, \"一号窗口\");
		Thread t2 = new Thread(tw, \"二号窗口\");
		Thread t3 = new Thread(tw, \"三号窗口\");
		t1.start();
		t2.start();
		t3.start();
	}
}

class TicketWindow implements Runnable {
	private AtomicInteger tickets = new AtomicInteger(100);

	@Override
	public void run() {
		while (tickets.get() > 0) { //这里还是会产生并发
			tickets.getAndDecrement();

			System.out.println(Thread.currentThread().getName() + \"卖出一张火车票,还剩\" + tickets + \"张\");

		}
	}
}
收藏 打印