线程
-
start() : 启动线程的唯一方式
-
setName() : 设置线程的名字 默认是Thread-0,Thread-1…
-
getName() : 获取线程的名字
-
setPriority() : 设置线程优先级
-
getPriority() : 获取线程优先级
-
static currentThread() : 获取当前线程的内存地址
-
static sleep() : 睡眠当前线程,参数是睡眠的毫秒数
-
静态的,和用哪个对象没关系,写在哪个线程中,就获取哪个线程对象,就睡眠哪个线程
-
stop已经过时,不推荐使用,因为可能会导致死锁
-
使用占位符的方式终止线程
-
join():合并 让当前线程等待指定线程执行完后再执行
-
yield() : 暂停当前线程,让位给其他等待中的线程执行
-
是个静态方法,使用Thread.yield() 进行调用
-
同优先级让位,不同优先级不让位
-
当多个线程有可能操作同一个数据的时候,
public static void main(String[] args) {
Thread t1 = new Processer();
Thread t2 = new Processer();
t1.setName("t1");
t2.setName("t2");
// 设置优先级为1
t1.setPriority(1);
// 设置优先级为10
t2.setPriority(10);
t1.start();
t2.start();
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + " --> " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Processer_02 p = new Processer_02();
Thread t1 = new Thread(p);
t1.setName("t1");
t1.start();
// t1线程是死循环,5秒后,终止它
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// stop已经过时,不推荐使用,因为可能会导致死锁
// t1.stop();
// 使用占位符的方式终止线程
p.flag = false;
}
public static void main(String[] args) {
Thread t1 = new Thread(new Processor_04());
t1.start();
for (int i = 0; i < 10; i++) {
// 让出当前执行的时间片,让其他等待的线程执行
Thread.yield();
System.out.println(Thread.currentThread().getName()+" : "+i);
}
}
锁
-
为了考虑数据的一致性和安全性,需要进行同步机制,
-
尤其是更改操作,查询无所谓,因为查询不会对数据发生更改
-
1 Lock 是显式锁,需要手动开启和手动关闭,而synchronized是隐式锁,除了作用域,自动解锁
-
2 Lock 只有代码块锁,而synchronized可以代码块锁,可以方法锁
*3 使用Lock还有更多功能扩展
-
死锁 : 就是大家在执行过程中,都遇到了对方进入加锁的方法,从而导致都访问不了的状态
1 ) 某个线程执行完成 , 需要 先后 嵌套 锁定两个对象,在这个过程中,该线程先锁定了第一个对象
2 ) 另一个线程执行完成 , 需要 先后 嵌套 锁定两个对象,在这个过程中,该线程先锁定了第二个对象
3 ) 第一个线程执行中,执行到锁第二个对象的时候,发现第二个对象被第二个线程锁住了,只能等待
4 ) 第二个线程执行中,执行到锁第一个对象的时候,发现第一个对象被第一个线程锁住了,只能等待 -
wait : 让当前线程进入挂起状态,并且会释放持有的锁 当被唤醒之后,进入就绪状态,当进入执行状态时,接着挂起的地方继续执行
-
wait() : 无参 不会自己醒,等待被唤醒 , 有参(毫秒数) 到点之后自己醒
-
notify : 随机唤醒一个在该对象中等待的线程
-
notifyAll : 唤醒在该对象中等待的所有线程
-
三个方法必须用在加锁的方法中
-
生产者和消费者
//synchronized锁
public void withDraw(double money) {
System.out.println("不需要同步的其他功能");
// 下面代码 需要同步执行
synchronized (this) {
// try {
// Thread.sleep(5000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
double after = balance - money;
balance = after;
System.out.println(Thread.currentThread().getName()
+ " --> 取款成功 : 1000.0 , 余额为 : " + balance);
}
}
//lock锁
public void withDraw(double money) {
System.out.println("不需要同步的其他功能");
// 加锁
lock.lock();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
double after = balance - money;
balance = after;
System.out.println(Thread.currentThread().getName()
+ " --> 取款成功 : 1000.0 , 余额为 : " + balance);
// 解锁
lock.unlock();
}
//死锁
public void run() {
// 当我们使用代码块锁,锁住o1的时候,那么 o1对象中的所有代码块锁和所有加锁的成员方法,全部锁定
synchronized (o1) {
// 加睡眠 是为了 让t2线程先锁住o2 , 保证一定死锁
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
// System.out.println("T1已经对o1加锁");
synchronized (o2) {
System.out.println("T1已经对o2加锁");
}
}
System.out.println("T1执行完成,o1和o2解锁");
}
public void run() {
synchronized (o2) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
// System.out.println("T2已经对o2加锁");
synchronized (o1) {
System.out.println("T2已经对o1加锁");
}
}
System.out.println("T2执行完成,o1和o2解锁");
}
多线程下安全的单例模式
private SingLeton_01() {
}
// 防止指令重排
private volatile static SingLeton_01 s = null;
public static SingLeton_01 getInstance() {
if (s == null) {
// 类锁,类中所有加锁的静态方法和语句块锁 全部锁定
synchronized(SingLeton_01.class){
// 双重校验
if ( s == null) {
s = new SingLeton_01();
}
}
}
return s;
}