public class ThreadCount extends Thread {
private Integer count = 0;
public ThreadCount(String name) {
this.setName(name);
}
@Override
public void run() {
while (count <5) {
System.out.println(Thread.currentThread().getName()+":"+count+"--->"+(++count));
}
}
public static void main(String[] args) {
ThreadCount a = new ThreadCount("A");
ThreadCount b = new ThreadCount("B");
ThreadCount c = new ThreadCount("C");
ThreadCount d = new ThreadCount("D");
ThreadCount e = new ThreadCount("E");
a.start();
b.start();
c.start();
d.start();
e.start();
}
}
运行结果(多次运行结果不一致,但最终结果都是每个线程的count值变为5):
内存模型:
方式一:
我们创建了3个线程,每个线程都有各自的count变量,自己减少自己的count变量的值.这样的情况就是变量不共享,并不存在多个线程访问同一个实例变量的情况.
方式二(多个线程操纵共享变量):
public class ThreadCount1 extends Thread {
private Integer count = 0;
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+":"+count+"--->"+(++count));
}
public static void main(String[] args) {
ThreadCount1 threadCount1 = new ThreadCount1();
Thread threadA = new Thread(threadCount1, "A");
Thread threadB = new Thread(threadCount1, "B");
Thread threadC = new Thread(threadCount1, "C");
Thread threadD = new Thread(threadCount1, "D");
Thread threadE = new Thread(threadCount1, "E");
threadA.start();
threadB.start();
threadC.start();
threadD.start();
threadE.start();
}
}
运行结果(多次运行结果不一致,count值可能为5可能不为5):
内存模型:
方式二:
我们还是新建了5个线程,但是他们是共享主内存中的count变量.我们改变共享变量中的值分为3步:
①.从主内存中取出
从运行结果就可以看出,线程B和A同时对count进行了处理,产生了线程安全的问题,使的最终结果变为了4.
注意:虽然System.out.println()
是同步的,但是count++操作确实在进入println()之前发生的
public void println(String x) {
synchronized (this) {
print(x);
newLine();
}
}
方式三(使用锁将count++进行同步):
①使用synchronized
进行同步,既能保证一致性又能保证原子性
@Override
public synchronized void run() {
System.out.println(Thread.currentThread().getName() + ":" + count + "--->" + (++count));
}
②…其它锁,ReentrantLock
等
运行结果(每次运行结果相同,count变为5):
方式三:使用锁进行同步,使的同一时间只有一个线程能够进行访问.(原理以后细讲)
???这里要注意只是用volatile(轻量级锁)只能保证可见性而不能保证count++操作的原子性
private volatile Integer count = 0;
运行结果(每次运行结果不同,count的值不一定为5)
可见性:即对于一个volatile的读总能看到(任意线程)对这个volatile变量最后的写入.(原理:内存屏蔽)
原子性:对任意单个volatile变量的读/写具有原子性,但类似于volatile++这种复合操作不具有原子性
count++并不是一个原子操作,它分为3步:
①.从内存中取出原有的count值
②.进行i++的操作
③.把count++后的值赋给count并写入到主内存
方式四(使用Atomic相关类):
private static AtomicInteger count = new AtomicInteger(0);
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ":" + count + "--->" + (count.incrementAndGet()));
}
运行结果(每次运行结果不相同,count变为5):
方式四:使用AtomicInteger
类并调用incrementAndGet
进行count++的操作.(原理:CAS)
方式五(使用java.util.concurrent(juc)
下的一些类,如CountDownLatch
或者CyclicBarrier
等)
因为我对juc下的一些类不太了解,以后深入理解了在来继续写