自增操作不是原子性的
要想并发程序正确地执行,必须要保证原子性、可见性以及有序性。只要有一个没有被保证,就有可能会导致程序运行不正确。。在并发编程中,我们通常会遇到以下三个问题:
- 原子性:即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行
- 可见性:可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。
- 有序性:即程序执行的顺序按照代码的先后顺序执行。如:指令重排序(Instruction Reorder)造成程序不按照正常顺序执行。
临界区:多个线程使用一个资源,这个资源进入临界区保护,只能一个线程访问,其他线程等待(阻塞),非阻塞允许多线程进入临界区
并发与并发:实线虚线表示不同任务
Thread t = new Thread(); t.start()与t.run():前者会新建一个线程,后者不会 只会在当前线程执行
Thread.run()源码实现
//Thread.run()的实现
//target 是Runnable接口
public void run() {
if (target != null) {
target.run();
}
}
1.重写run()
Thread t1=new Thread(){
@Override
public void run(){
System.out.println("Hello, I am t1");
}
};
t1.start();
2.直接传入target 查看线程构造函数初始化代码
Thread t1=new Thread(new CreateThread3());
t1.start();
Thread.interrupt()线程中断
public void Thread.interrupt() // 中断线程
public boolean Thread.isInterrupted() // 判断是否被中断
public static boolean Thread.interrupted() // 判断是否被中断,并清除当前中断状态
-----------------------------------------------------------------------
public void run(){
while(true){
if(Thread.currentThread().isInterrupted()){
System.out.println("Interruted!");
break;
}
Thread.yield();
}
}
public void run(){
while(true){
if(Thread.currentThread().isInterrupted()){
System.out.println("Interruted!");
break;
}
try {
Thread.sleep(2000);
}
catch (InterruptedException e) {
System.out.println("Interruted When Sleep");
//设置中断状态,抛出异常后会清除中断标记位
Thread.currentThread().interrupt();
}
Thread.yield();
}
}
@deprecate注解 表示不推荐使用
挂起( suspend)和继续执行( resume)线程 不推荐使用 suspend()不会释放锁
等待线程结束( join)和谦让(yeild)
//join的本质
while(isAlive()){
wait(0);
}
jps:java自带的查看java进程的工具
在后台默默地完成一些系统性的服务,比如垃圾回收线程、JIT线程就可以理解为守护线程,当一个Java应用内,只有守护线程时,Java虚拟机就会自然退出
Thread t=new DaemonT();
t.setDaemon(true);
t.start();
高优先级的线程更容易再竞争中获胜 并不保证
synchronized关键字 jvm内部中实现的
- 指定加锁对象:对给定的对象加锁,进入同步代码前要获得给定的对象的锁
- 直接作用于实例方法:相当于对当前实例加锁,进入同步代码前要获得当前实例的锁
- 直接作用于静态方法:相当于对当前类加锁,进入同步代码前要获的当前类的锁
public class Demo {
static AccountingSync instance = new AccountingSync();
public static class AccountingSync implements Runnable {
static int i;
public synchronized void increase(){
i++;
}
public void run() {
for (int j = 0; j<1000000; j++){
increase();//给实例方法加锁,作用于实例方法上,不同线程必须操作同一实例,否则结果testSynchronized_diffInstance
// synchronized(instance){//给对象实例进行加锁
// i++;
// }
}
}
}
public static class AccountingSync_static implements Runnable {
static int k;
public synchronized static void increase1(){
k++;
}
public void run() {
for (int j = 0; j<1000000; j++){
increase1();
}
}
}
public static void main(String[] args) throws InterruptedException {
//testSynchronized();
testSynchronized_diffInstance();
}
private static void testSynchronized_diffInstance() throws InterruptedException {
//执行结果 如果两个线程new两个不同实例,结果小于2000000,如果synchronized作用于静态方法,相当于作用于类上
Thread thread1 = new Thread(new AccountingSync());
Thread thread2 = new Thread(new AccountingSync());
thread1.start(); thread2.start();
thread1.join(); thread2.join();
System.out.println("作用于类方法上"+AccountingSync.i);
//执行结果2000000 作用于静态方法上 相当于作用于类上 即使new不同实例
Thread thread3 = new Thread(new AccountingSync_static());
Thread thread4 = new Thread(new AccountingSync_static());
thread3.start(); thread4.start();
thread3.join(); thread4.join();
System.out.println("作用于静态类方法上"+AccountingSync_static.k);
}
private static void testSynchronized() throws InterruptedException {
//执行结果 如果不加关键字synchronized执行结果小于200000线程不安全(多个线程操作同一个资源),加上执行结果等于200000
Thread thread1 = new Thread(instance);
Thread thread2 = new Thread(instance);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(AccountingSync.i);
}
}