并发编程 (2020-02)

线程的创建方式

在这里插入图片描述

    public Create01(String name) {
        super(name);
    }

    @Override
    public void run() {
        while (!interrupted()) {
            System.out.println(this.getName() + "线程执行了");
        }
    }

    public static void main(String[] args) {
        Create01 create01 = new Create01("first");   //Thread-0线程执行了
        Create01 create02 = new Create01("second");   //Thread-1线程执行了
        create01.start();
        create02.start();
    }
/**
 * 作为线程任务存在
 */
public class Create02 implements Runnable {
    @Override
    public void run() {
        while (true){
            System.out.println("thread running");
        }
    }
    public static void main(String[] args) {
        Thread thread = new Thread(new Create02());
        thread.run();
    }
}
    public static void main(String[] args) {
        new Thread() {
            @Override
            public void run() {
                System.out.println("thread run");
            }
        }.start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("runnable run");
            }
        }) {
            public void run() {
                System.out.println("runnable2 run");
            }
        }.start();
    }
    thread run
	runnable2 run
public class Create04 implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        System.out.println("计算中");
        Thread.sleep(2000);
        return 3;
    }

    public static void main(String[] args) throws Exception {
        Create04 create04 = new Create04();
        FutureTask<Integer> task = new FutureTask<>(create04);
        new Thread(task).start();
        System.out.println("我先干别的");
        Integer integer = task.get();
        System.out.println(integer);
    }
}
计算中
我先干别的
3
   public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("hahah");
            }
        },0,1000);
    }
    hahah
	hahah
    public static void main(String[] args) {
        ExecutorService threadPool = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            threadPool.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            });
        }
        threadPool.shutdown();
    }
@Service
public class Create07 {
    @Async
    public void a() throws InterruptedException {
        while (true){
            System.out.println("a");
            Thread.sleep(2000);
        }

    }
    @Async
    public void b() throws InterruptedException {
        while (true){
            System.out.println("b");
            Thread.sleep(2000);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);
        Create07 bean = ac.getBean(Create07.class);
        bean.a();
        bean.b();
    }
}

@Component
@ComponentScan("com.cy.create")
@EnableAsync
public class Config {

}
b
a
b
a
    public int add(List<Integer> list){
        list.parallelStream().forEachOrdered(System.out::println);
        return 0;
    }

    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(10, 20, 30);
        int res = new Create08().add(list);
        System.out.println("计算结果:"+res);
    }
10
20
30
计算结果:0

线程的状态

在这里插入图片描述

线程活跃性问题

死锁
饥饿	
活锁

饥饿与公平:
	高优先级吞噬所有低优先级的CPU时间片
	线程被永久堵塞在一个等待进入同步块的状态
	等待线程不被唤醒				
如何避免:
	合理设置优先级
	使用锁来代替synchronized

优先级

public class YouXianJi implements Runnable{
    public static void main(String[] args) {
        Thread thread1 = new Thread(new YouXianJi());
        Thread thread2 = new Thread(new YouXianJi());

        thread1.setPriority(Thread.MIN_PRIORITY);
        thread2.setPriority(Thread.MAX_PRIORITY);

        thread1.start();
        thread2.start();
    }
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getId());
    }
}

Synchronized加锁防止多线程安全问题

public class Question_Safe {

    private  int value = 0;

    public  synchronized int add() {
        return value++;
    }

    public static void main(String[] args) {
        Question_Safe question_safe = new Question_Safe();
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    System.out.println(Thread.currentThread().getName() + ":" + question_safe.add());
                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                        System.out.println(Thread.currentThread().getName() + ":" + question_safe.add());
                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    System.out.println(Thread.currentThread().getName() + ":" + question_safe.add());
                }
            }
        }).start();
    }
}
总结:线程安全性问题:
		多线程环境
		多线程共享资源
		对资源进行非原子性操作

Synchronized原理与使用(自行释放锁):

synchronized字节码指令:
	monitorenter:进入
	  MyMethod();
	monitorexit:退出
任何对象都可以作为锁 那么锁信息又存在于对象的什么地方呢?
	存储在对象头中
对象头中有什么信息?
	Mark Word 
	CLass Metadata Address
	Array Length

锁的分类

偏向锁: 
	每次获取锁和释放锁都会浪费资源
	很多情况下 竞争锁不是由多个线程 而是由一个线程在使用
	Mark Word : 
		线程id
		对象的分代年龄信息
		是否是偏向锁
		锁标志位
轻量级锁:
	自旋
	多个线程可以同时
重量级锁

单例模式与线程安全性问题

在这里插入图片描述

锁重入

在已经获得锁的同步方法或同步代码块内部可以调用锁定对象的其他同步方法, 不需要重新获取锁.
public class ChongRu_Lock {
    public synchronized void a() {
        System.out.println("a");
        b();
    }

    public synchronized void b() {
        System.out.println("b");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                new ChongRu_Lock().a();
            }
        }).start();
    }
}

自旋锁

是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。
public class ZiXuan_Lock {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "线程开始执行");
                try {
                    Thread.sleep(new Random().nextInt(2000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "线程执行完毕");
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "线程开始执行");
                try {
                    Thread.sleep(new Random().nextInt(2000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "线程执行完毕");
            }
        }).start();
        int i = Thread.activeCount();
        while (i != 1) {
            //自旋
        }
        System.out.println("所有线程执行完毕");
    }

}

死锁

public class Die_Lock {
	
	private Object obj1 = new Object();
	private Object obj2 = new Object();
	
	
	public void a () {
		synchronized (obj1) {
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			synchronized (obj2) {
				System.out.println("a");
			}
		}
	}
	
	public void b () {
		synchronized (obj2) {
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			synchronized (obj1) {
				System.out.println("b");
			}
		}
	}
	
	public static void main(String[] args) {

		Die_Lock d = new Die_Lock();
		
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				d.a();
			}
		}).start();
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				d.b();
			}
		}).start();
	}

}

Volatile

轻量级锁,被Volatile修饰的变量 线程之间是可见的
可见:一个线程修改了这个变量的值 在另外一个线程中可以读到修改后的值
Synchronized除了线程之间互斥以外 还有一个大作用 就是保证可见性

/**
 * 保证可见性的前提
 * 多个线程拿到的是同一把锁,否则是保证不了的。
 */
public class Volatile {

    public volatile int a = 1;

    public synchronized int getA() {
        return a++;
    }

    public synchronized void setA(int a) {
        try {
            Thread.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        this.a = a;
    }

    public static void main(String[] args) {

        Volatile demo = new Volatile();

        demo.a = 10;

        new Thread(new Runnable() {

            @Override
            public void run() {
                System.out.println(demo.a);
            }
        }).start();

        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("最终的结果为:" + demo.getA());
    }
}
    public volatile boolean run = false;

    public static void main(String[] args) {

        Volatile2 d = new Volatile2();

        new Thread(new Runnable() {

            @Override
            public void run() {
                for(int i = 1;i<=10;i++) {
                    System.err.println("执行了第 " + i + " 次");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                d.run = true;
            }
        }).start();

        new Thread(new Runnable() {

            @Override
            public void run() {
                while(!d.run) {
                    // 不执行
                }
                System.err.println("线程2执行了...");
            }
        }).start();

Volatile JVM指令分析

Lock:
	在多处理器的系统上:
			将当前处理器缓存行的内容写回到系统内存
			写个写回到内存的操作会使在其他CPU缓存了改内存地址的数据失败
	硬盘-内存-CPU缓存(最小单位:缓存行)	

JDK通过的原子类的原理的使用(JDK1.5提出)

java.util.concurrent.atomic
public class Sequence {
	
	private AtomicInteger value  = new AtomicInteger(0);

	private int [] s = {2,1,4,6};
	
	AtomicIntegerArray a = new AtomicIntegerArray(s);

	AtomicReference<User> user = new AtomicReference<>();
	
	AtomicIntegerFieldUpdater<User> old =  AtomicIntegerFieldUpdater.newUpdater(User.class, "old");
	
	/**
	 * @return
	 */
	public  int getNext() {
		
		User user = new User();
		System.out.println(old.getAndIncrement(user));
		System.out.println(old.getAndIncrement(user));
		System.out.println(old.getAndIncrement(user));

		a.getAndIncrement(2);
		a.getAndAdd(2, 10);
		return value.getAndIncrement();
	}
	
	public static void main(String[] args) {
		
		Sequence s = new Sequence();
		
		new Thread(new Runnable() {
			
			@Override
			public void run() {
//				while(true) {
					System.out.println(Thread.currentThread().getName() + " " + s.getNext());
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
//				}
			}
		}).start();
		
//		new Thread(new Runnable() {
//			
//			@Override
//			public void run() {
//				while(true) {
//					System.out.println(Thread.currentThread().getName() + " " + s.getNext());
//					try {
//						Thread.sleep(100);
//					} catch (InterruptedException e) {
//						e.printStackTrace();
//					}
//				}
//			}
//		}).start();
//		
//		new Thread(new Runnable() {
//			
//			@Override
//			public void run() {
//				while(true) {
//					System.out.println(Thread.currentThread().getName() + " " + s.getNext());
//					try {
//						Thread.sleep(100);
//					} catch (InterruptedException e) {
//						e.printStackTrace();
//					}
//				}
//			}
//		}).start();
		
	}

}

Lock接口的认识和使用

	相比synchornized:
		Lock需要获取和释放锁  繁琐让代码灵活
		Synchronized不需要显示释放和获取锁 简单
	使用Lock方便实现公平性
		非阻塞的获取锁
		能被中断的获取锁
		超时获取锁
public class LockTest {
    private int value;
    Lock lock = new ReentrantLock();
    Lock l1 = new ReentrantLock();

    public int getNext() {
        lock.lock();
        int a = value++;
        lock.unlock();
        return a;
    }

    public static void main(String[] args) {

        Sequence s = new Sequence();

        new Thread(new Runnable() {

            @Override
            public void run() {
                while (true) {
                    System.out.println(Thread.currentThread().getName() + " " + s.getNext());
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();

        new Thread(new Runnable() {

            @Override
            public void run() {
                while (true) {
                    System.out.println(Thread.currentThread().getName() + " " + s.getNext());
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();

        new Thread(new Runnable() {

            @Override
            public void run() {
                while (true) {
                    System.out.println(Thread.currentThread().getName() + " " + s.getNext());
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }
}

AQS(AbstractQueuedSynchronizer)

通过AQS实现自己的锁(可重入)

public class MyAQSLock implements Lock {

    private Helper helper = new Helper();
    
    private class Helper extends AbstractQueuedSynchronizer {
        @Override
        protected boolean tryAcquire(int arg) {
            //第一个线程进来 可以拿到锁 返回true
            //第二个线程进来 拿不到锁 返回false
            //如何判断是第几个线程进来
            int state = getState();
            Thread thread = Thread.currentThread();

            if (state == 0) {
                if (compareAndSetState(0, arg)) {
                    setExclusiveOwnerThread(thread);
                    return true;
                }
            } else if (getExclusiveOwnerThread() == thread) {
                setState(state + 1);
                return true;
            }
            return false;
        }
        @Override
        protected boolean tryRelease(int arg) {
            //锁的获取和释放肯定是一一对应的,那么调用此方法的线程一定是当前的线程
            if (Thread.currentThread() != getExclusiveOwnerThread()) {
                throw new RuntimeException();
            }
            int state = getState() - arg;

            boolean flag = false;
            if (getState() == 0) {
                setExclusiveOwnerThread(null);
                flag = true;
            }
            setState(state);
            return flag;
        }

        public Condition newConditoion() {
            return new ConditionObject();
        }
    }
    @Override
    public void lock() {
        helper.acquire(1);
    }
    @Override
    public void lockInterruptibly() throws InterruptedException {
        helper.acquireInterruptibly(1);
    }
    @Override
    public boolean tryLock() {
        return helper.tryAcquire(1);
    }
    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return helper.tryAcquireNanos(1, unit.toNanos(time));
    }
    @Override
    public void unlock() {
        helper.release(1);
    }
    @Override
    public Condition newCondition() {
        return helper.newConditoion();
    }
}
public class MyAQSLockTest {

    private int value;
    private MyAQSLock lock = new MyAQSLock();

    public int next() {
        lock.lock();
        try {
            Thread.sleep(300);
            return value++;
        } catch (InterruptedException e) {
            throw new RuntimeException();
        } finally {
            lock.unlock();
        }
    }

    public void a() {
        lock.lock();
        System.out.println("a");
        b();
        lock.unlock();
    }

    public void b() {
        lock.lock();
        System.out.println("b");
        lock.unlock();
    }

    public static void main(String[] args) {

        MyAQSLockTest m = new MyAQSLockTest();

        new Thread(() -> {
            m.a();
        }).start();

    }
}

公平锁

针对锁的获取而言的,如果一个锁是公平的,那么锁的获取顺序就应该符合请求的绝对时间顺序

读写锁

排他锁与共享锁
public class ReadWriteLock {

    private Map<String, Object> map = new HashMap<>();

    private java.util.concurrent.locks.ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    private Lock readLock = readWriteLock.readLock();
    private Lock writeLock = readWriteLock.writeLock();

    public Object get(String key) {
        readLock.lock();
        System.out.println("读:" + Thread.currentThread().getName());
        try {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return map.get(key);
        } finally {
            readLock.unlock();
            System.out.println("读完了:" + Thread.currentThread().getName());
        }
    }

    public Object put(String key, Object object) {
        writeLock.lock();
        System.out.println("写:" + Thread.currentThread().getName());
        try {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return map.put(key, object);
        } finally {
            writeLock.unlock();
            System.out.println("写完了:" + Thread.currentThread().getName());
        }
    }
}
public class ReadWriteLockTest {
    public static void main(String[] args) {
        ReadWriteLock lock = new ReadWriteLock();
        lock.put("key1", "value1");

        new Thread((() -> {
            lock.get("key1");
        })).start();
        new Thread((() -> {
            lock.get("key1");
        })).start();
//        new Thread((() -> {
//            lock.put("key1","value3");
//        })).start();
//        new Thread((() -> {
//            lock.put("key2","value3");
//        })).start();
//        new Thread((() -> {
//            lock.put("key3","value3");
//        })).start();
    }
}
读写锁:读锁与读锁之间不排斥 读锁与写锁之间排斥 写锁和写锁之间排斥
读写锁需要保存的状态:
	写锁重入的次数
	读锁的个数
	每个读锁重入的次数
	
1111 1111 1111 1111(读锁重入个数) - 1111 1111 1111 1111(写锁重入个数)  (int:代表重入的次数)

锁降级 写锁降级为读锁

在写锁的没有释放的时候 获取到读锁 再释放到写锁

	private boolean isUpdate;

    public void readWrite() {
        readLock.lock();
        if (isUpdate) {
            readLock.unlock();
            writeLock.lock();
            map.put("xxx", "xxx");
            readLock.lock();
            writeLock.unlock();
        }
        Object xxx = map.get("xxx");
        System.out.println(xxx);
        readLock.unlock();
    }

锁升级 读锁升级为写锁

在读锁还没有释放的时候 获取到写锁 再释放读锁

线程安全性问题总结

出现线程安全性问题的条件
	在多线程的环境下
	必须有共享资源
	对共享资源进行非原子性操作
解决线程安全性问题的途径
	Synchronized(偏向锁 轻量级锁 重量级锁)
	Volatile(关键词)
	JDK提供的原子类(	java.util.concurrent.atomic.*)
	Lock接口
认识的锁
	偏向锁
	轻量级锁
	重量级锁
	重入锁
	自旋锁
	共享锁
	独占锁
	排他锁
	读写锁
	公平锁
	非公平锁
	死锁
	活锁

线程间通信

wait notify
消费者生产者模型
Condition
Join(加塞)
public class TJoin {
    public void a(Thread joinThread) {

        System.out.println("a start");
        joinThread.start();
        try {
            joinThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("a finish");
    }

    public void b() {
        System.out.println("加塞线程 start");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("加塞线程 finish");
    }

    public static void main(String[] args) {
        TJoin tJoin = new TJoin();
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                tJoin.b();
            }
        });
        new Thread(() -> {
            tJoin.a(thread);
        }).start();
    }
}
ThreadLocal
public class TThreadLocal {
    private ThreadLocal<Integer> count = new ThreadLocal<Integer>(){
        @Override
        protected Integer initialValue() {
            return 0;
        }
    };

    public int getNext() {
        Integer value = count.get();
        value++;
        count.set(value);
        return value;
    }

    public static void main(String[] args) {
        TThreadLocal t = new TThreadLocal();
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    System.out.println(Thread.currentThread().getName() + ":" + t.getNext());
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    System.out.println(Thread.currentThread().getName() + ":" + t.getNext());
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    System.out.println(Thread.currentThread().getName() + ":" + t.getNext());
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }
}
并发工具类:CountDownLatch(汇总线程)
发布了19 篇原创文章 · 获赞 6 · 访问量 1978

猜你喜欢

转载自blog.csdn.net/qq_42252844/article/details/104348238
今日推荐