Java核心类库篇7——多线程
1、程序、进程和线程
- 程序 - 数据结构 + 算法,主要指存放在硬盘上的可执行文件
- 进程 - 主要指运行在内存中的可执行文件
- 线程就是进程内部的程序流
操作系统内部支持多 进程的,而每个进程的内部又是支持多线程的
2、线程的创建
方法声明 | 功能介绍 |
public Thread() | 使用无参的方式构造对象 |
public Thread(String name) | 根据参数指定的名称来构造对象 |
public Thread(Runnable target) | 根据参数指定的引用来构造对象,其中Runnable是个接口类型 |
public Thread(Runnable target, String name) | 根据参数指定引用和名称来构造对象 |
public void run() | 若使用Runnable引用构造了线程对象,调用该方法时最终调 用接口中的版本 若没有使用Runnable引用构造线程对象,调用该方法时则啥也不做 |
public void start() | 用于启动线程,Java虚拟机会自动调用该线程的run方法 |
public long getId() | 获取调用对象所表示线程的编号 |
public String getName() | 获取调用对象所表示线程的名称 |
public void setName(String name) | 设置/修改线程的名称为参数指定的数值 |
public static Thread currentThread() | 获取当前正在执行线程的引用 |
2.1、继承Thread类
- 优点:实现起来简单,而且要获取当前线程,无需调用Thread.currentThread()方法,直接使用this即可获取当前线程
- 缺点:线程类已经继承Thread类了,就不能再继承其他类,多个线程不能共享同一份资源
public class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 50; i++) {
System.out.println(this.getName()+"----------------"+i);
}
}
}public class Test {
public static void main(String[] args) {
new MyThread().start();
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName()+"----------------"+i);
}
}
}注:直接调用run方法如同调用类成员方法一样
2.2、实现Runnable接口
- 优点:线程类只是实现了接口,还可以继承其他类,多个线程可以使用同一个target对象,适合多个线程处理同一份资源的情况
- 缺点:通过这种方式实现多线程,相较于第一类方式,编程较复杂,要访问当前线程,必须调用Thread.currentThread()方法
public class MyRunable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName()+"----------------"+i);
}
}
}public class Test {
public static void main(String[] args) {
new Thread(new MyRunable()).start();
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName()+"----------------"+i);
}
}
}2.3、Callable和FutureTask
- 优点:线程类只是实现了接口,还可以继承其他类,多个线程可以使用同一个target对象,适合多个线程处理同一份资源的情况
- 缺点:通过这种方式实现多线程,相较于第一类方式,编程较复杂,要访问当前线程,必须调用Thread.currentThread()方法
public class Test {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<Integer> futureTask=new FutureTask<Integer>(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName()+"----------------"+i);
}
return 100;
}
});
new Thread(futureTask, "ruoye").start();
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName()+"----------------"+i);
}
System.out.println(futureTask.get());
}
}lambda表达式
public class Test {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<Integer> futureTask = new FutureTask<>((Callable<Integer>) () -> {
System.out.println("hello world!");
return 100;
});
new Thread(futureTask, "ruoye").start();
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName()+"----------------"+i);
}
System.out.println(futureTask.get());
}
}3、线程优先级及线程让步
方法声明 | 功能介绍 |
public static void yield() | 当前线程让出处理器(离开Running状态),使当前线程进入Runnable 状态等待 |
public static void sleep(times) | 使当前线程从 Running 放弃处理器进入Block状态, 休眠times毫秒 |
public int getPriority() | 获取线程的优先级 |
public void setPriority(int newPriority) | 修改线程的优先级,优先级越高的线程不一定先执行,但该线程获取到时间片的机会会更多 一些 |
public void join() | 等待该线程终止 |
public void join(long millis) | 等待参数指定的毫秒数 |
public boolean isDaemon() | 用于判断是否为守护线程 |
public void setDaemon(boolean on) | 用于设置线程为守护线程 |
sleep
public class Test {
public static void main(String[] args) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
while (true){
System.out.println(simpleDateFormat.format(new Date()));
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}setPriority线程优先级
public class Test {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
System.out.println(Thread.currentThread().getName()+"优先级-----"+Thread.currentThread().getPriority());
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+"-----"+i);
}
});
thread.setName("ruoye");
thread.setPriority(Thread.MAX_PRIORITY);
thread.start();
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+"-----"+i);
}
}
}线程等待
public class Test {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-----"+i);
}
});
thread.setName("ruoye");
thread.start();
// thread.join();
// System.out.println("终于等到你");
thread.join(5000);
System.out.println("没有等到你");
}
}守护线程
public class Test {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-----"+i);
}
});
thread.setName("ruoye");
thread.setDaemon(true);
thread.start();
Thread.sleep(5000);
System.out.println("没有等到你");
}
}4、线程同步
4.1、多线程出现的问题
public class Account implements Runnable {
private int money;
public Account(int money) {
this.money = money;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
@Override
public void run() {
System.out.println("进到门口");
System.out.println("开始取钞");
if (this.money>200){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.money-=200;
System.out.println("取款成功");
}
}
@Override
public String toString() {
return "Account{" +
"money=" + money +
'}';
}
}public class Test {
public static void main(String[] args) throws InterruptedException {
Account account = new Account(1000);
Thread thread = new Thread(account);
Thread thread1 = new Thread(account);
thread.start();
thread1.start();
thread.join();
thread1.join();
System.out.println(account.getMoney());
}
}4.2、synchronized同步锁
4.2.1、synchronized代码块
下面所示为锁class,锁Account对象里的成员变量(对象)也可,但请时刻记住,多个Account为对象里的成员变量(对象)多个对象,那么就拥有了多把锁,此时应当用static修饰
休眠在同步代码块内不会让出cpu
public class Account implements Runnable {
private int money;
public Account(int money) {
this.money = money;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
@Override
public void run() {
System.out.println("进到门口");
synchronized (Account.class){
System.out.println("开始取钞");
if (this.money>200){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.money-=200;
System.out.println("取款成功");
}
}
}
@Override
public String toString() {
return "Account{" +
"money=" + money +
'}';
}
}public class Test {
public static void main(String[] args) throws InterruptedException {
Account account = new Account(1000);
Thread thread = new Thread(account);
Thread thread1 = new Thread(account);
thread.start();
thread1.start();
thread.join();
thread1.join();
System.out.println(account.getMoney());
}
}4.2.2、synchronized方法
当synchronized位于成员方法上等价于synchronized (this)
当当synchronized位于成员方法上等价于synchronized (类对象)
public class Account implements Runnable {
private int money;
public Account(int money) {
this.money = money;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
@Override
public synchronized void run() {
System.out.println("进到门口");
System.out.println("开始取钞");
if (this.money>200){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.money-=200;
System.out.println("取款成功");
}
}
@Override
public String toString() {
return "Account{" +
"money=" + money +
'}';
}
}public class Test {
public static void main(String[] args) throws InterruptedException {
Account account = new Account(1000);
Thread thread = new Thread(account);
Thread thread1 = new Thread(account);
thread.start();
thread1.start();
thread.join();
thread1.join();
System.out.println(account.getMoney());
}
}4.3、死锁问题
尽量减少同步的资源,减少同步代码块的嵌套结构的使用
线程一执行的代码
public void run(){
synchronized(a){
//持有对象锁a,等待对象锁b
synchronized(b){
//编写锁定的代码;
}
}
}线程二执行的代码
public void run(){
synchronized(b){
//持有对象锁a,等待对象锁b
synchronized(a){
//编写锁定的代码;
}
}
}4.4、Lock锁
- Lock是显式锁,需要手动实现开启和关闭操作,而synchronized是隐式锁,执行锁定代码后自动释放
- Lock只有同步代码块方式的锁,而synchronized有同步代码块方式和同步方法两种锁
- 使用Lock锁方式时,Java虚拟机将花费较少的时间来调度线程,因此性能更好
public class Account implements Runnable {
private int money;
private static Lock lock=new ReentrantLock();
public Account(int money) {
this.money = money;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
@Override
public void run() {
lock.lock();
System.out.println("进到门口");
System.out.println("开始取钞");
if (this.money>200){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.money-=200;
System.out.println("取款成功");
}
lock.unlock();
}
@Override
public String toString() {
return "Account{" +
"money=" + money +
'}';
}
}public class Test {
public static void main(String[] args) throws InterruptedException {
Account account = new Account(1000);
Thread thread = new Thread(account);
Thread thread1 = new Thread(account);
thread.start();
thread1.start();
thread.join();
thread1.join();
System.out.println(account.getMoney());
}
}5、线程通信
5.1、线程通信
不能锁class
public class Account implements Runnable {
private int a;
public Account(int a) {
this.a = a;
}
@Override
public void run() {
while (true){
synchronized (this) {
if (a<100){
System.out.println(Thread.currentThread().getName()+"========"+a);
a++;
notify();
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else{
break;
}
}
}
}
}public class Test {
public static void main(String[] args) throws InterruptedException {
Account account = new Account(1);
Thread ruoye = new Thread(account, "ruoye");
Thread yoya = new Thread(account, "yoya");
ruoye.start();
yoya.start();
}
}5.2、生产者消费者问题
- 线程间的通信共享数据一定要有同步代码块synchronized
- 一定要有wait和notify,而且二者一定是成对出现
- 生产者和消费者的线程实现一定是在while(true)里面
public class Mother implements Runnable {
private Account account;
public Mother(Account account) {
this.account = account;
}
@Override
public void run() {
while (true){
try {
account.produce();
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}public class Ming implements Runnable {
private Account account;
public Ming(Account account) {
this.account = account;
}
@Override
public void run() {
while (true){
try {
account.consumer();
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}public class Account {
private int a;
public Account(int a) {
this.a = a;
}
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public synchronized void produce() throws InterruptedException {
notify();
if (a<2000){
a+=100;
System.out.println("妈妈给小明存了100元");
}else{
wait();
}
}
public synchronized void consumer() throws InterruptedException {
notify();
if (a>75){
a-=75;
System.out.println("小明花了75元");
}else{
wait();
}
}
}public class Test {
public static void main(String[] args) throws InterruptedException {
Account account = new Account(0);
new Thread(new Mother(account)).start();
new Thread(new Ming(account)).start();
}
}
















