线程
线程终止
① 因为 run 方法正常退出而自然死亡
② 因为一个没有捕获的异常终止了 run 方法而意外死亡
线程状态
线程优先级
每一个线程有一个优先级。默认情况下, 一个线程继承它的父线程的优先级。 可以用 setPriority
方法提高或降低任何一个线程的优先级。可以将优先级设置为在 MIN_PRIORITY
(在 Thread 类中定义为 1 ) 与 MAX_PRIORITY (定义为 10 ) 之间的任何值。NORM_PRIORITY
被定义为 5。
创建一个线程方式
方式一:继承Thread类
/**
步骤:
1. 声明一个类,让其继承Thread类,该类成为子类
2. 重写Thread类的run方法
3. 调用该类 的 实例并 start
public static void main(String[] args) {
MyThread myThread = new MyThread();
//start() 作用:
/**
Causes this thread to begin execution; 执行该线程
the Java Virtual Machine calls the run method of this thread. 调用 当前线程 run
*/
myThread.start();
}
class MyThread extends Thread{
@Override
public void run() {
//do something
System.out.println("具体处理");
}
}
// 线程常用方法
System.out.println(MyThread.currentThread()); Thread[main,5,main]
System.out.println(myThread.getName()); Thread-0
方式一的卖票问题
public class ThreadTest {
public static void main(String[] args) {
Ticket ticket = new Ticket();
ticket.start();
Ticket ticket1 = new Ticket();
ticket1.start();
Ticket ticket2 = new Ticket();
ticket2.start();
}
}
class Ticket extends Thread{
static int ticket = 10;
@Override
public void run() {
while (true){
if (ticket > 0){
System.out.println(Thread.currentThread().getName()+"票数:"+ticket);
ticket--;
}else {
break;
}
}
}
}
/**
结果:
Thread-0票数:5
Thread-0票数:4
Thread-0票数:3
Thread-0票数:2
Thread-0票数:1
Thread-1票数:5
Thread-2票数:5
*/
方式二:实现Runnable接口
/**
1. 编写一个类 实现Runnable接口
2. 实现接口中run方法
3. 创建该类对象,把此对象当作参数传递给Thread构造器中,创建Thread对象
4. 通过Thread对象调用start方法
public static void main(String[] args) {
MyThread2 myThread2 = new MyThread2();
Thread thread = new Thread(myThread2);
thread.start();
}
}
class MyThread2 implements Runnable{
@Override
public void run() {
//doSomething
System.out.println("doSomething");
}
}
*/
方式二的卖票问题
public class ThreadTest1 {
public static void main(String[] args) {
Target2 target2 = new Target2();
Thread thread = new Thread(target2);
thread.start();
Thread thread1 = new Thread(target2);
thread1.start();
Thread thread2 = new Thread(target2);
thread2.start();
}
}
class Target2 implements Runnable{
int target2 = 5;
@Override
public void run() {
//doSomething
while (true){
if (target2 > 0){
System.out.println(Thread.currentThread().getName()+"票数:"+target2);
target2--;
}else {
break;
}
}
}
}
/**
结果:
Thread-0票数:5
Thread-0票数:4
Thread-0票数:3
Thread-0票数:2
Thread-2票数:5
Thread-2票数:1
Thread-1票数:5
*/
创建线程的第三种方式Callable-尚未补充
//待补充
创建线程的第四种方式 线程池:Executors-尚未补充
//待补充
线程安全-synchronized方式
/**
对两种创建线程的方式 进行加锁处理,该处理有两种解决方案,
同步代码块和同步方法。
对共享的代码进行加锁处理,多个线程需要共用一把锁
*/
public class ThreadTest1 {
public static void main(String[] args) {
Target2 target2 = new Target2();
Thread thread = new Thread(target2);
thread.start();
Thread thread1 = new Thread(target2);
thread1.start();
Thread thread2 = new Thread(target2);
thread2.start();
}
}
class Target2 implements Runnable{
int target2 = 5;
@Override
public void run() {
//doSomething
while (true){
synchronized (this){ //this表示当前对象,在此处且唯一
if (target2 > 0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"票数:"+target2);
target2--;
}else {
break;
}
}
}
}
}
/** 结果:
Thread-1票数:5
Thread-1票数:4
Thread-1票数:3
Thread-1票数:2
Thread-1票数:1
*/
public class ThreadTest {
public static void main(String[] args) {
Ticket ticket = new Ticket();
ticket.start();
Ticket ticket1 = new Ticket();
ticket1.start();
Ticket ticket2 = new Ticket();
ticket2.start();
}
}
class Ticket extends Thread{
static int ticket = 5;
private static Object o = new Object(); //对象o唯一
@Override
public void run() {
while (true){
synchronized (o){ //o可替换为 Ticket.class
if (ticket > 0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"票数:"+ticket);
ticket--;
}else {
break;
}
}
}
}
}
/** 结果:
Thread-0票数:5
Thread-0票数:4
Thread-0票数:3
Thread-0票数:2
Thread-0票数:1
*/
// 也可用同步方法改写,把共享代码写入一个方法中,加synchronized关键字即可。如:
public synchronized void methodName(){};
线程安全-Reentrant 方式
// 用 ReentrantLock 保护代码块的基本结构如下:
myLock.lock(); // a ReentrantLock object
try{
critical section
}
finally{
myLock.unlockO;// make sure the lock is unlocked even if an exception is thrown
}
example
public class ReentrantTest {
public static void main(String[] args) {
test1();
}
public static void test1(){
Ticket2 ticket2 = new Ticket2();
Thread thread = new Thread(ticket2);
thread.start();
Thread thread1 = new Thread(ticket2);
thread1.start();
Thread thread2 = new Thread(ticket2);
thread2.start();
}
}
class Ticket2 implements Runnable{
private int ticket = 100;
private ReentrantLock lock = new ReentrantLock(); //第三种方式
@Override
public void run() {
while (true){
try {
lock.lock(); //锁住
if (ticket > 0){
System.out.println(Thread.currentThread().getName()+"票数:"+ticket);
ticket--;
}else {
break;
}
}finally {
lock.unlock(); //开锁
}
}
}
}
synchronized 和 ReentrantLock的区别
ReentrantLock 需要手动上锁 和 手动解锁
条件对象 Condition
待补充
线程通信
/**
wait(): 表示 当前线程进入 阻塞 状态,并释放同步监视器
notify(): 唤醒 被阻塞(wait)的线程,若有多个线程被阻塞,则唤醒优先级高的线程
notifyAll(): 唤醒所有被阻塞的线程
这三个方法必须 放在同步代码块和同步方法中;
这三个方法必须是同步代码块或同步方法中和监视器同一个对象;
这三个方法都位于Object类中
*/
public class ReentrantTest {
public static void main(String[] args) {
test2();
}
public static void test2(){
Clock c1 = new Clock();
c1.start();
Clock c2 = new Clock();
c2.start();
}
}
class Clock extends Thread{
private static int count = 10;
@Override
public void run() {
while (true){
synchronized (Clock.class){
Clock.class.notify(); //表示 唤醒被阻塞(wait())的线程;notifyAll: 唤醒所有阻塞线程
if (count >= 0){
System.out.println(Thread.currentThread().getName()+"\t"+count);
count--;
try {
Clock.class.wait(); //wait和notify需要和监视器一致
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
break;
}
}
}
}
}
sleep 和 wait 异同
- 都可以表示 线程 阻塞
- sleep 位于 Thread类中,wait位于Object类中
- sleep 任何 场景调用,wait 只能在同步代码块或同步方法中调用
- 若两个方法都用在了 同步代码块或同步方法中,则wait 可以释放同步监视器,sleep不会释放同步监视器