版权声明:未经允许,随意转载,请附上本文链接谢谢(づ ̄3 ̄)づ╭❤~
http://blog.csdn.net/xiaoduan_/article/details/79343229
多线程
多线程的创建有3种方法
- 继承 Thread 类,重写 run()方法,run()方法代表线程要执行的任务。
- 实现 Runnable 接口,重写 run()方法,run()方法代表线程要执行的任务。
- 实现Runnable接口方法存在的必要性?
- java不支持多继承
- 不打算重写Thread类的其他方法
- 实现 callable 接口,重写 call()方法,call()作为线程的执行体,具有返回值,并且可以
对异常进行声明和抛出;使用 start()方法来启动线程
Thread类
构造方法 | 说明 |
---|---|
Thread() | 创建一个线程对象 |
Thread(String name) | 创建一个具有指定名称的线程对象 |
Thread(Runnable target) | 创建一个基于Runnable接口实现类的线程对象 |
Thread(Runnable target, String name) | 创建一个基于Runnable接口实现类,并且具有指定名称的线程对象 |
常用方法 | 说明 |
---|---|
public void run() | 线程相关的代码写在该方法中,一般需要重写 |
public void start() | 启动线程的方法 |
public static void sleep(long n) | 线程休眠m毫秒的办法 |
public void join() | 优先执行调用join()方法的线程,阻塞其他线程,执行本线程 |
Runnable接口
- 只有一个方法run()
- Runnable是java中实现线程的接口
- 任何实现线程功能的类都必须实现该接口
线程的状态
- 新建(New)
- 可运行(Runnable)
- 正在运行(Running)
- 阻塞(Blocked)
- 终止(Dead)
线程的生命周期
sleep方法
public static void sleep(long millis)
作用:在指定的毫秒数内让正在执行的线程休眠(暂停执行)参数为休眠的时间,单位是毫秒
join方法应用
public final void join()
作用:等待调用该方法的线程结束后才能执行
public final void jion(long millis)
作用:等待该线程终止的最长时间为millis毫秒,如果millis为0,意味着要一直等下去
线程优先级
- java为线程类提供10个优先级
- 优先级可以用整数1-10表示,超过范围会抛出异常
- 主线程默认优先级为5
- 优先级常量
MAX_PRIORITY
:线程的最高优先级10MIN_PRIORITY
:线程的最低优先级1NORM_PRIOITY
:线程的默认优先级5
- 优先级相关方法
public int getPriority()
: 获取线程优先级的方法public void setPriority(int newPriority)
:设置线程优先级方法
多线程运行时的随机问题
- 各个线程是通过竞争CPU时间而获得运行机会的
- 各线程什么时候得到CPU时间,占用多久,是不可预测的
- 一个正在运行的线程在什么地方被暂停是不确定的
同步
- synchronized关键字可以用在
- 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。
- 成员方法
public synchronized void saveAccount(){}
被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象 - 静态方法
public static synchronized void saveAccount(){}
其作用的范围是整个静态方法,作用的对象是这个类的所有对象 - 语句块
synchronized (obj){......}
被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
- 无论synchronized关键字加在方法上还是对象上,如果它作用的对象是非静态的,则它取得的锁是对象;如果synchronized作用的对象是一个静态方法或一个类,则它取得的锁是对类,该类所有的对象同一把锁。
- 每个对象只有一个锁(lock)与之相关联,谁拿到这个锁谁就可以运行它所控制的那段代码。
- 实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。
线程间通信
wait()
:中断方法的执行,使线程等待notify()
:随机唤醒处于等待的某一个线程,使其结束等待notifyAll()
:唤醒所有处于等待的线程,使他们结束等待
实现Callable接口创建线程
- 创建 Callable 接口的实现类,并实现 call()方法,该 call()方法将作为线程执行体,并且 有返回值。
- 创建 Callable 实现类的实例,使用 FutureTask 类来包装 Callable 对象,该 FutureTask 对象封装了该 Callable 对象的 call()方法的返回值。
- 使用 FutureTask 对象作为 Thread 对象的 target 创建并启动新线程。
- 调用 FutureTask 对象的 get()方法来获得子线程执行结束后的返回值。
例子
package com.company;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
* @Description:测试Callable多线程的练习
* @Date: Created in 13:43 2018/2/21
* @Author: Anthony_Duan
*/
public class ThiridThread implements Callable<String >{
@Override
public String call() throws Exception {
String str = "这是用Callable接口实现的多线程";
return str;
}
}
class ThiridThreadTest{
public static void main(String[] args) {
Callable<String> call = new ThiridThread();
FutureTask<String> ft = new FutureTask<>(call);
Thread t = new Thread(ft);
t.start();
try {
System.out.println(ft.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
银行账户典型案例
/**
* 银行账户类
*/
class Account {
String name;
float amount;
public Account(String name, float amount) {
this.name = name;
this.amount = amount;
}
//存钱
public void deposit(float amt) {
amount += amt;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//取钱
public void withdraw(float amt) {
amount -= amt;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public float getBalance() {
return amount;
}
}
/**
* 账户操作类
*/
class AccountOperator implements Runnable{
private Account account;
public AccountOperator(Account account) {
this.account = account;
}
public void run() {
synchronized (account) {
account.deposit(500);
account.withdraw(500);
System.out.println(Thread.currentThread().getName() + ":" + account.getBalance());
}
}
}
测试代码
Account account = new Account("zhang san", 10000.0f);
AccountOperator accountOperator = new AccountOperator(account);
final int THREAD_NUM = 5;
Thread threads[] = new Thread[THREAD_NUM];
for (int i = 0; i < THREAD_NUM; i ++) {
threads[i] = new Thread(accountOperator, "Thread" + i);
threads[i].start();
}
在AccountOperator 类中的run方法里,我们用synchronized 给account对象加了锁。这时,当一个线程访问account对象时,其他试图访问account对象的线程将会阻塞,直到该线程访问account对象结束。也就是说谁拿到那个锁谁就可以运行它所控制的那段代码。
结果
Thread3:10000.0
Thread2:10000.0
Thread1:10000.0
Thread4:10000.0
Thread0:10000.0