线程和高并发
线程:作为一个进程里面最小的执行单元它就叫一个线程,用简单的话讲一个程序里不同的执行路径就叫做一个线程
进程:做一个简单的解释,你的硬盘上有一个简单的程序,这个程序叫QQ.exe,这是一个程序,这个程序是一个静态的概念,它被扔在硬盘上也没人理他,但是当你双击它,弹出一个界面输入账号密码登录进去了,OK,这个时候叫做一个进程。进程相对于程序来说它是一个动态的概念
private static class T1 extends Thread {
启动线程的三种方式:
1.从Thread类中集成
2.实现Runnable接口
3.从线程池中启动
public class T02_HowToCreateThread {
static class MyThread extends Thread {
获得当前线程的名字:Thread.currentThread().getName()
睡眠:sleep
谦让的退出一下:yield
等待另个线程结束,可以按顺序进行:join
线程正常结束即可关闭,不建议用stop。
回顾并发小程序
public class Test03 implements Runnable{
private int i=10;
有锁将票数完整输出
synchronized
我们对一个数字做递增,两个程序对它一块儿来做递增,递增就是把一个程序往上加1啊,如果两个线程共同访问的时候,第一个线程一读它是0,然后把它加1,在自己线程内部内存里面算还没有写回去的时候而第二个线程读到了它还是0,加1在写回去,本来加了两次,但还是1,那么我们在对这个
/**
*synchronized关键字
*对某个对象加锁
*@author mashibing
*/
package com.mashibing.juc.c_001;
public class T {
private int count = 10;
private Object o = new Object();
public void m() {
synchronized(o) { //任何线程要想执行下面的代码,必须先拿到o的锁
count--;
System.out.println(Thread.currentThread().getName() + " count = " +
count);
}}}
如果说你每次都定义个一个锁的对象Object o 把它new出来那加锁的时候太麻烦每次都要new一个新的对象出来,所以呢,有一个简单的方式就是 synchronized(this)锁定当前对象就行
/**
* synchronized关键字
* 对某个对象加锁
* @author mashibing
*/
package com.mashibing.juc.c_002;
public class T {
private int count = 10;
public void m() {
synchronized(this) { ߳//任何线程想要执行那个下面的代码,必须先要拿到this的锁
count--;
System.out.println(Thread.currentThread().getName() + " count = " + count);}}}
如果你要是锁定当前对象呢,你也可以写成如下方法。synchronized方法和synchronized(this)执行这段代码它是等值的
package com.mashibing.juc.c_003;
public class T {
private Aint count = 10;
public synchronized void m() { //等同于在方法的代码执行时要synchronized(this)
count--;
System.out.println(Thread.currentThread().getName() + " count = " + count);
}
}
有锁无锁同时使用
package com.mashibing.juc.c_007;
public class T {
public synchronized void m1() {
System.out.println(Thread.currentThread().getName() + " m1 start...");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " m1 end");
}
public void m2() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " m2 ");
}
public static void main(String[] args) {
T t = new T();
/*new Thread(()->t.m1(), "t1").start();
new Thread(()->t.m2(), "t2").start();*/
new Thread(t::m1, "t1").start();
new Thread(t::m2, "t2").start();
/*
//1.8之前的写法
new Thread(new Runnable() {
@Override
public void run() {
t.m1();
}
});
*/
}
}
可重入
如果是一个同步方法调用另外一个同步方法,有一个方法加了锁,另外一个方法也需要加锁,加的是同一把锁也是同一个线程,那这个时候申请仍然会得到该对象的锁。比如说是synchronized可重入的,有一个方法m1 是synchronized有一个方法m2也是synchrionzed,m1里能不能调m2。我们m1开始的时候这个线程得到了这把锁,然后在m1里面调用m2,如果说这个时候不允许任何线程再来拿这把锁的时候就死锁了。这个时候调m2它发现是同一个线程,因为你m2也需要申请这把锁,它发现是同一个线程申请的这把锁,允许,可以没问题,这就叫可重入锁。