目录
多线程并不是真正意义上的并行执行,而是多个线程交替性抢占CPU资源,
谁获取了CPU资源就执行谁在执行过程中,有可能丢失CPU资源,被另外一个线程执行,所以会出现交替执行的现象。但是以人肉眼无法观察到计算机中的交替执行,故而可以看作为多线程。
一、线程中的基本方法
//获取线程优先级的最大值/最小值/默认值
System.out.println(Thread.MAX_PRIORITY);//10
System.out.println(Thread.MIN_PRIORITY);//1
System.out.println(Thread.NORM_PRIORITY);//5
//获取当前正在运行的线程对象
Thread thread =Thread.currentThread();
//获取当前线程对象的名称
String name =thread.getName();
System.out.println("当前运行线程的名称:"+name);//main
//获取当前线程的id
long num =thread.getId();
System.out.println(num);//1
//获取当前线程的优先级
int priorty =thread.getPriority();
System.out.println(priorty);//5
//获取当前线程的状态
Thread.State state =thread.getState();
System.out.println(state);//RUNNABLE
//设置线程的名称
thread.setName("葵花点穴手");
System.out.println(thread.getName());//葵花点穴手
//设置线程优先级
thread.setPriority(8);
System.out.println(thread.getPriority());//8
String str = thread.toString();
System.out.println(str);//Thread[葵花点穴手,8,main]
二、线程的两种实现方法
第一种方法
(1) 第一步:创建MyThread类,继承Thread类
(2)第二步:重写run()方法
(3)第三步;在run()方法中编写线程运行代码
(4)第四步:创建线程类对象,并用start()方法启动线程
第二种方法
(1)第一步;创建MyRunnable类,实现Runnable接口
(2)第二步:重写run()方法
(3)第三步:在run()方法中编写线程运行代码
(4)第四步:创建MyRunnable类对象,由于MyRunnable没有start()方法,所以用Thread将其封装为一个线程对象,再用start()方法启动线程
三、线程睡眠
当当前线程遇到想让其暂停一段时间的条件时,可以使用sleep方法使其睡眠一段时间后再自动运行。
@Override
public void run() {
for (int i = 1; i <=10; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
if(i==5){
try {
// 睡眠5秒后执行
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
MyRunnable3 mr = new MyRunnable3();
Thread t = new Thread(mr);
t.start();
}
四、线程礼让
线程礼让:让当前执行run()方法的线程释放CPU资源,给其它线程一个获得CPU资源的机会,
但是当前线程还会抢占CPU资源,也就是说,当前线程释放CPU资源后,会与其它线程再一次抢占CPU,就看其它线程能不能抓住这个机会。
public static void main(String[] args) {
MyRunnable5 mr = new MyRunnable5();
Thread t1 = new Thread(mr, "线程A");
Thread t2 = new Thread(mr, "线程B");
t1.start();
t2.start();
}
@Override
public void run() {
for (int i = 1; i <= 10; i++) {
System.out.println(Thread.currentThread().getName() + "正在运行:" + i);
if (i == 3) {
System.out.print("线程礼让:");
Thread.yield();
}
}
}
五、线程同步机制
当多线程并发的环境下,有共享数据,并且这个数据还会被修改,此时就存在线程安全问题,
怎么解决这个问题?
线程排队执行。(不能并发).用排队执行解决线程安全问题。
这种机制被称为:线程同步机制。
此时就需要使用synchronized,synchronized(syncObject)就是为当前的线程声明一把锁
syncObject是同步的对象,一般为this。
多个并发线程访问同一资源的同步代码块时,同一时刻只能有一个线程进入synchronized(this)同步代码块。
当一个线程访问一个synchronized(this)同步代码块时,其他synchronized(this)同步代码块同样被锁定。
当一个线程访问一个synchronized(this)同步代码块时,其他线程可以访问该资源的非synchronized(this)同步代码。
应用:使用synchronized两个取钱线程进行限制,使其无法同时对账户进行取钱,以此来保护线程安全。
private String actno;
private double balance;
public Account() {
}
public Account(String actno, double balance) {
this.actno = actno;
this.balance = balance;
}
public String getActno() {
return actno;
}
public void setActno(String actno) {
this.actno = actno;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
// 取款方法
public synchronized void withdraw(double money){
double before = this.getBalance();
double after = before-money;
// 网络延迟,导致两个线程同时进行,不安全
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.setBalance(after);
}
public class AccountThread extends Thread{
// 两个线程必须共享同一个账户对象
private Account act;
// 通过构造方法传递过来账户对象
public AccountThread(Account act) {
this.act = act;
}
// run方法执行表示取款操作
public void run(){
double money = 5000;
act.withdraw(money);
System.out.println(Thread.currentThread().getName()+"对"+act.getActno()+"取款成功,余额:"+act.getBalance());
}
}
public static void main(String[] args) {
// 创建账户对象
Account account = new Account("act-001",10000);
// 创建两个线程
Thread t1 = new AccountThread(account);
Thread t2 = new AccountThread(account);
t1.setName("t1");
t2.setName("t2");
// 启动线程
t1.start();
t2.start();
}