线程常用方法
-
setName //设置线程名称
-
getName //返回该线程名称
-
start //使该线程开始执行;Java虚拟机调用该线程的start0方法
-
run //调用线程对象run方法
-
setPriority //更改现成的优先级
-
getPriority //获取线程的优先级
-
sleep //在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)
-
interrput //中断线程
-
yield: //线程的礼让。让出cpu,让其他线程执行,但礼让的时间不确定,所以也不一定礼让成功
-
join //线程的插队。插队的线程一旦插队成功,则肯定先执行完插入的线程所有的任务
public class SellTicket {
public static void main(String[] args) throws InterruptedException {
SellTicket01 sellTicket01 = new SellTicket01();
Thread thread1 = new Thread(sellTicket01);
//设置线程名称
thread1.setName("一号");
//更改线程优先级1:Thread.MAX_PRIORITY 5:Thread.NORM_PRIORITY 10:Thread.MAX_PRIORITY
thread1.setPriority(1);
//获取线程优先级
int a = thread1.getPriority();
System.out.println(a);
//获取线程名称
String name = thread1.getName();
System.out.println(name);
//开始执行线程
thread1.start();
//休眠1000毫秒
Thread.sleep(1000);
//线程礼让
Thread.yield();
//线程的插队
thread1.join();
new Thread(sellTicket01).start();
new Thread(sellTicket01).start();
}
}
class SellTicket01 implements Runnable{
private static int ticketNum = 100;
@Override
public void run() {
while (true){
if(ticketNum <=0){
System.out.println("售票结束");
break;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("窗口" + Thread.currentThread().getName() + "售出一张票,剩余票数:"+(--ticketNum));
}
}
}
用户线程与守护线程Daemon
- 用户线程:也叫工作线程,当线程的任务完成或通知方式结束
- 守护线程:一般是为工作线程服务的,当所有的用户线程结束,守护线程自动结束
- 常见的守护线程:垃圾回收机制
public class Demo2 {
public static void main(String[] args) throws InterruptedException {
MyDaemonThread myDaemonThread = new MyDaemonThread();
//设为保护线程(main线程结束之后,子线程自动结束)
myDaemonThread.setDaemon(true);
myDaemonThread.start();
for (int i = 0; i < 5; i++) {
System.out.println("吃包子" + i);
Thread.sleep(1000);
}
}
}
class MyDaemonThread extends Thread{
@Override
public void run() {
while (true){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("嘿嘿嘿");
}
}
}
/*
吃包子0
吃包子1
嘿嘿嘿
吃包子2
吃包子3
嘿嘿嘿
吃包子4
*/
线程的状态
public class State {
public static void main(String[] args) throws InterruptedException {
T t = new T();
System.out.println(t.getName()+"状态"+t.getState());
t.start();
while (Thread.State.TERMINATED != t.getState()){
System.out.println(t.getName()+"状态"+t.getState());
Thread.sleep(1000);
}
System.out.println(t.getName()+"状态"+t.getState());
/*
Thread-0状态NEW
Thread-0状态RUNNABLE
hi0
Thread-0状态TIMED_WAITING
hi1
Thread-0状态TIMED_WAITING
hi2
Thread-0状态TIMED_WAITING
Thread-0状态TERMINATED
*/
}
}
class T extends Thread{
@Override
public void run() {
while (true){
for (int i = 0; i < 3; i++) {
System.out.println("hi"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
break;
}
}
}
线程同步机制
在多线程编程,一些敏感数据不允许被多个线程同时访问,此时就是用同步访问技术,在保证数据在任何时刻,最多有一个线程访问,以保证数据的完整性
同步具体方法:Synchronized
- 同步代码块
synchronized(对象){ //得到对象的锁才能同步代码
//需要被同步代码
}
- synchronized还可以放在方发声明中,表示整个方法为同步方法
public synchronized viod m(String name){
//需要同步的代码
}
示例:
public class Synchronized_ {
public static void main(String[] args) {
SellTicket01 sellTicket01 = new SellTicket01();
new Thread(sellTicket01).start();
new Thread(sellTicket01).start();
new Thread(sellTicket01).start();
}
}
//实现接口方式,使用是synchronized实现线程同步
class SellTicket01 implements Runnable{
private static int ticketNum = 10;
private boolean loop = true;
public synchronized void sell() { //同步方法,在同一时刻只能有一个线程来执行sell方法
if(ticketNum <=0){
System.out.println("售票结束");
loop = false;
return;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("窗口" + Thread.currentThread().getName() + "售出一张票,剩余票数:"+(--ticketNum));
}
@Override
public void run() {
while (loop){
sell(); //sell方法是同步方法
}
}
}
/*
窗口Thread-0售出一张票,剩余票数:9
窗口Thread-0售出一张票,剩余票数:8
窗口Thread-1售出一张票,剩余票数:7
窗口Thread-1售出一张票,剩余票数:6
窗口Thread-2售出一张票,剩余票数:5
窗口Thread-2售出一张票,剩余票数:4
窗口Thread-1售出一张票,剩余票数:3
窗口Thread-0售出一张票,剩余票数:2
窗口Thread-1售出一张票,剩余票数:1
窗口Thread-2售出一张票,剩余票数:0
售票结束
售票结束
售票结束
*/
互斥锁
- Java语言中,引入了互斥锁概念,来保证共享数据操作的完整性
- 每个对象都对应一个可称为“互斥锁”的标记,这个标记用来保证在任意时刻,只能有一个线程访问该对象
- 关键字synchronized来与对象的互斥锁联系,当某个对象用synchronized修饰时,表明该对象在任一时刻只能有一个线程访问
- 同步的局限性:导致程序的执行效率降低
- 同步方法(非静态的)的锁可以是this,也可以是其他对象(要求是同一个对象)
- 同步方法(静态的)的锁为当前类本身
注意:
1. 同步方法如果没有使用static修饰,默认锁对象为this
2. 如果方法使用static修饰,默认锁对象:当前类.class
线程的死锁、释放
死锁:多个线程都占用了对方的锁资源,但不肯相让,导致了死锁。在编程中一定要避免死锁的发生
下面的操作会释放锁:
- 当前线程的同步方法、同步代码块执行结束
- 当前线程在同步代码块、同步方法中遇到break、return
- 当前线程在同步代码快、同步方法中出现了未处理的Error或Exception,导致异常结束
- 当前线程在同步代码快、同步方法中执行了线程对象的wait()方法,当前线程暂停,并释放锁
下面的操作不会释放锁:
-
线程执行同步代码块或同步方法时,程序调用了Thread.sleep(), Thread.yield()方法暂停了当前线程的执行,不会释放锁
-
线程执行同步代码块时,其他线程调用了该线程的suspend()将该线程挂起,该线程不对释放锁
注意:应尽量避免使用suspend()和 resume()来控制线程,不推荐使用