1.线程
线程(thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务
2.守护线程
- 守护线程是特殊的线程,一般用于在后台为其他线程提供服务.(主线程结束,守护线程就结束)
- Java中,isDaemon():判断一个线程是否为守护线程.
- Java中,setDaemon():设置一个线程为守护线程.
3.实现线程两种方式
1.继承java.lang.Thread类并重写run()方法,在run()方法编写线程要执行的任务。
-
启动方式:new ThreadDemo ().start();
2.实现java.lang.Runnable 接口并实现run()方法.(需要用thread包装启动)
-
启动方式:ThreadDemo r = new ThreadDemo ();
-
①new Thread(r).start();
-
还有匿名内部类,lambdas实现方式;
4.对比两种方式
1.继承thread类;
package threadReview;
/**
* @author lz先生
* @Date: 2020/3/21/021
*/
public class MyThreadTest extends Thread {
public MyThreadTest() {
/*设置守护线程主线程结束,此线程结束*/
setDaemon(true);
}
@Override
public void run() {
while (true) {
System.out.println(this.getName() + ":MyThreadTest执行完毕线程名字");
try {
sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new MyThreadTest().start();
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("MyThreadTest执行完毕");
}
}
2.实现Runnable接口
package threadReview;
/**
* @author lz先生
* @Date: 2020/3/21/021
*/
public class MyRunnableTest implements Runnable {
public MyRunnableTest() {
}
@Override
public void run() {
while (true) {
System.out.println("myRunnableTest线程:" + Thread.currentThread().getName());
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
MyRunnableTest myRunnableTest = new MyRunnableTest();
new Thread(myRunnableTest).start();
}
}
3.区别
- 实现Runnable接口不能再构造方法里设置为守护线程
- 获得线程名字需要用Thread.currentThread().getName()
- Runnable不能直接用sleep方法;需要用Thread.sleep(200);
-Runnable 启动需要thread类包装;
5.synchronized
是Java中的关键字,是一种同步锁。它修饰的对象有以下几种:
- 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象
- 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
- 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
- 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用的对象是这个类的所有对象。
当有一个线程访问被修饰部分时,其他线程将被阻塞;
1.runnable中的synchronize
package threadReview;
/**
* @author lz先生
* @Date: 2020/3/21/021
*/
public class SynchronizedTest implements Runnable {
private static int count;
public SynchronizedTest() {
count = 0;
}
@Override
public void run() {
synchronized (this) {
for (int i = 0; i < 5; i++) {
System.out.println(count++ + "线程名字" + Thread.currentThread().getName());
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
1.两个线程访问同一个对象的锁的时候1先执行完Synchronized修饰的内容,其次是线程2执行;
public static void main(String[] args) {
/*一个对象*/
SynchronizedTest tests = new SynchronizedTest();
new Thread(tests,"syn1").start();
new Thread(tests,"syn2").start();
/*结果
0线程名字syn1
1线程名字syn1
2线程名字syn1
3线程名字syn1
4线程名字syn1
5线程名字syn2
6线程名字syn2
7线程名字syn2
8线程名字syn2
9线程名字syn2
*/
}
2.两个线程访问不同对象的锁的时候执行是没有次序的;
public static void main(String[] args) {
/*两个对象*/
//SynchronizedTest tests = new SynchronizedTest();
new Thread(new SynchronizedTest(),"syn1").start();
new Thread(new SynchronizedTest(),"syn2").start();
/*结果
1线程名字syn2
0线程名字syn1
2线程名字syn1
3线程名字syn2
4线程名字syn1
4线程名字syn2
5线程名字syn2
6线程名字syn1
7线程名字syn1
8线程名字syn2
*/
}
2.thread中的synchronize
需要传一个对象作为用来锁的东西;
此处的对象ArrayList;…string类和Integer类不行;
package threadReview;
import java.util.ArrayList;
import java.util.List;
/**
* @author lz先生
* @Date: 2020/3/21/021
*/
public class SynchronizeThreadTest extends Thread {
List<Object> container;
private int count;
public SynchronizeThreadTest(String name, List<Object> container) {
super(name);
this.container = container;
}
@Override
public void run() {
for (int i = 0; i < 5; i++) {
synchronized (container) {
// 仓库没满,可以放物品
container.add(new Object());
this.count++;
System.out.println("生产者:" + getName() + " 共生产了:" + this.count + "件物品,当前仓库里还有" + container.size() + "件物品");
try {
sleep(150);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
ArrayList<Object> lock = new ArrayList<>();
new SynchronizeThreadTest("小白", lock).start();
new SynchronizeThreadTest("小黑", lock).start();
}
}
/*
结果
生产者:小白 共生产了:1件物品,当前仓库里还有1件物品
生产者:小黑 共生产了:1件物品,当前仓库里还有2件物品
生产者:小白 共生产了:2件物品,当前仓库里还有3件物品
生产者:小白 共生产了:3件物品,当前仓库里还有4件物品
生产者:小白 共生产了:4件物品,当前仓库里还有5件物品
生产者:小白 共生产了:5件物品,当前仓库里还有6件物品
生产者:小黑 共生产了:2件物品,当前仓库里还有7件物品
生产者:小黑 共生产了:3件物品,当前仓库里还有8件物品
生产者:小黑 共生产了:4件物品,当前仓库里还有9件物品
生产者:小黑 共生产了:5件物品,当前仓库里还有10件物品
*/
6.lock锁
import java.util.List;
import java.util.concurrent.locks.Lock;
public class Producer extends Thread{
List<Object> container;
/*表示当前线程共生产了多少件物品*/
private int count;
// 一个可重入的互斥锁 Lock,
//它具有与使用 synchronized 方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,
private Lock lock;
public Producer(String name, List<Object> container, Lock lock) {
super(name);
this.container = container;
this.lock = lock;
}
@Override
public void run() {
while (true) {
// 加锁
lock.lock();
try {
// 对仓库的同步操作
if(this.container.size()<10){
// 仓库没满,可以放物品
container.add(new Object());
this.count++;
System.out.println("生产者:" + getName() +
" 共生产了:" + this.count + "件物品,当前仓库里还有" + container.size() + "件物品");
}
}finally {
// 解锁
lock.unlock();
}
try {
sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
7.锁
当多个线程需要访问某个公共资源的时候,需要通过加锁来保证资源的访问不会出问题。
java提供了两种方式来加锁,
-
一种是关键字:synchronized,一种是concurrent包下的lock锁。
-
synchronized是java底层支持的,而concurrent包则是jdk实现。
lock的基本操作还是通过乐观锁来实现的
sync是悲观锁,是java底层支持的
本质来说,就是悲观锁认为总会有人抢我的。
乐观锁就认为,基本没人抢