v# 1. 线程基本概念
(1)单核CPU实现多任务;(2)同一个CPU,在某个时刻,多个任务交替执行;CPU速度很快,造成“QQ”和“迅雷”貌似同时执行的错觉;
(1)在同一个时刻多个任务同时执行,多核CPU可以实现并行;
用代码模拟实现Runnable接口实现线程的机制;
public class Thread02 {
public static void main(String[] args) {
Tiger tiger = new Tiger();//实现了Runnable接口
ThreadProxy threadProxy = new ThreadProxy(tiger);
threadProxy.start();
}
}
实现步骤: 先创建一个Proxy类,继承Runnable
class ThreadProxy implements Runnable {//把Proxy类当作 ThreadProxy 线程代理
private Runnable target = null;
@Override
public void run() {
if (target != null) {
target.run();//动态绑定(运行类型Tiger)
}
}
public ThreadProxy(Runnable target) {
this.target = target;
}
public void start() {
start0();//真正实现多线程的方法
}
public void start0() {
run();
}
}
class Tiger extends Animal implements Runnable{
@Override
public void run() {
System.out.println("老虎发威~~");
}
}
sleep()要在–tickets前面才能超卖
public class SellTicket {
public static void main(String[] args) {
/*SellTicket1 sellTicket1 = new SellTicket1();
SellTicket1 sellTicket2 = new SellTicket1();
SellTicket1 sellTicket3 = new SellTicket1();
sellTicket1.start();
sellTicket2.start();
sellTicket3.start();*/
SellTicket1 sellTicket1 = new SellTicket1();
Thread thread1 = new Thread(sellTicket1);
Thread thread2 = new Thread(sellTicket1);
Thread thread3 = new Thread(sellTicket1);
thread1.start();
thread2.start();
thread3.start();
}
}
class SellTicket1 extends Thread {
//private static int tickets = 100;
private int tickets = 100;
int count = 0;
@Override
public void run() {
while (true) {
if (tickets <= 0) {
break;
}
System.out.println("窗台:" + Thread.currentThread().getName() +
"出售了" + (++count) + "张票,剩余票数:" + (--tickets));
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
启动一个线程t,要求在main线程中去停止线程t
解决方案:在主线程中通过Setter方法将loop变量设置为false
方法名 | 作用 |
---|---|
setName | 设置线程名称 |
getName | 获取线程名称 |
setPriority | 设置线程优先级 |
getPriority | 获取线程优先级 |
interrupt | 中断线程 |
public class ThreadMethod_ {
public static void main(String[] args) throws InterruptedException {
T t = new T();
t.setName("赵志伟");//设置线程名称
t.setPriority(Thread.MIN_PRIORITY);//设置线程优先级
t.start();//启动了子线程
System.out.println(t.getName());//获取线程名称
//主线程打印5个hi,然后就中断子线程的休眠
for (int i = 0; i < 5; i++) {
Thread.sleep(1000);
System.out.println("hi~~" + i);
}
System.out.println(t.getName() + "线程的优先级" + t.getPriority());
t.interrupt();//执行到interrupt()方法时,中断线程的休眠
}
}
class T extends Thread {
@Override
public void run() {
while (true) {
for (int i = 0; i < 100; i++) {
//获取当前线程的名称
System.out.println(Thread.currentThread().getName() + " 吃包子~~" + i);
}
try {
System.out.println(Thread.currentThread().getName() + " 正在休眠中~~");
Thread.sleep(20 * 1000);
} catch (InterruptedException e) {
//当该线程执行到一个interrupt 方法时,就会catch 一个异常,可以加入自己的业务代码
// InterruptedException捕获了一个中断异常
System.out.println(Thread.currentThread().getName() + "被中断了");
}
}
}
}
yield:线程的礼让,让出cpu,让其它线程执行,但礼让的时间不确定,所以不一定礼让成功;
join:线程插队,一旦插入成功,则先执行完插入的线程的所有的任务;
public class Thread03 {
public static void main(String[] args) throws InterruptedException {
T t = new T();
Thread thread = new Thread(t);
thread.start();
for (int i = 1; i <= 20; i++) {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + "(小弟)吃了" + i + "个");
if (i == 10) {
System.out.println("main线程(小弟)让子线程(大哥)先吃");
// thread.join();//子线程(大哥)插队,大哥吃完小弟再吃
Thread.yield();//main线程(小弟)礼让,不一定成功...
}
}
}
}
class T implements Runnable {
private int count = 0;
private boolean loop = true;
@Override
public void run() {
while (loop) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("子线程(老大)吃了" + (++count) + "个");
if (count == 20) {//吃到20个结束
System.out.println("子线程(大哥)吃完了,main线程(小弟)继续吃");
break;
}
}
}
public void setLoop(boolean loop) {
this.loop = loop;
}
}
public class ThreadMethodExercise {
public static void main(String[] args) throws InterruptedException {
T1 t1 = new T1();
Thread thread = new Thread(t1);
for (int i = 1; i <= 10; i++) {
Thread.sleep(1000);
System.out.println("main线程:hi " + i);
if (i == 5) {
thread.start();
thread.join();//子线程启动后直接插队
}
}
}
}
class T1 implements Runnable {
private int count;
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("子线程: hello " + (++count));
if (count == 10) {
break;
}
}
}
}
用户线程:也叫工作线程、当线程的任务执行完或通知方式结束;
守护线程:一般是为工作线程服务的,当所有的用户线程结束,守护线程自动结束;
常见的守护线程:垃圾回收机制;
主线程结束,子线程并不会结束;如果我们希望主线程结束时,子线程也结束,可以将子线程设置为守护线程;
public class ThreadMehod03 {
public static void main(String[] args) {
MyDaemonThread myDaemonThread = new MyDaemonThread();
Thread thread = new Thread(myDaemonThread);
thread.setDaemon(true);//将子线程设置为守护线程
thread.start();
for (int i = 1; i <= 10; i++) {
System.out.println("主线程" + Thread.currentThread().getName() + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class MyDaemonThread implements Runnable {
@Override
public void run() {
for (; ; ) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("子线程" + Thread.currentThread().getName());
}
}
}
public class ThreadState_ {
public static void main(String[] args) throws InterruptedException {
T2 t2 = new T2();
Thread thread = new Thread(t2);
System.out.println(thread.getName() + "状态 " + thread.getState());//NEW
thread.start();
//子线程和主线程同时执行
/*for (int i = 0; i < 10; i++) {
Thread.sleep(1000);//主线程休眠、主线程输出
System.out.println(thread.getName() + "状态 " + thread.getState());//RUNNABLE
}*/
while (Thread.State.TERMINATED != thread.getState()) {
Thread.sleep(1000);
System.out.println(thread.getName() + "状态 " + thread.getState());//RUNNABLE、TIMED_WAITING
}
System.out.println(thread.getName() + "状态 " + thread.getState());//TERMINATED
}
}
class T2 implements Runnable {
@Override
public void run() {
while (true) {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);//子线程输出
try {
Thread.sleep(1000);//子线程休眠
} catch (InterruptedException e) {
e.printStackTrace();
}
}
break;
}
}
}
Java语言中,引入了对象互斥锁的概念,来保证共享数据操作的完整性;
每个对象都对应一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象;
关键字synchronized来与对象的互斥锁联系,当某个对象用synchronized修饰时,表明该对象在任一时刻只能由一个线程访问;
同步的局限性:会导致程序的执行效率降低;
同步方法(静态的)的锁为当前类本身;
方法上加锁、代码块上加锁;
同步方法如果没有使用static修饰,默认锁对象为this;
public class DeadLock_ {
public static void main(String[] args) {
DeadLockDemo deadLockDemo = new DeadLockDemo(true);
deadLockDemo.setName("A线程");
deadLockDemo.start();
DeadLockDemo deadLockDemo1 = new DeadLockDemo(false);
deadLockDemo1.setName("B线程");
deadLockDemo1.start();
}
}
class DeadLockDemo extends Thread {
static Object o1 = new Object();//保证多线程,共享一个对象,使用static
static Object o2 = new Object();
boolean flag;
public DeadLockDemo(boolean flag) {//构造器
this.flag = flag;
}
@Override
public void run() {
//(1)如果flag为true,线程A 就会先得到/持有 o1对象锁,然后尝试去获取o2对象锁
//(2)如果flag为true,线程A 就会先得到/持有 o1对象锁,然后尝试去获取o2对象锁
if (flag) {
synchronized (o1) {
System.out.println(Thread.currentThread().getName() + "进入1");
synchronized (o2) {
System.out.println(Thread.currentThread().getName() + "进入2");
}
}
} else {
synchronized (o2) {
System.out.println(Thread.currentThread().getName() + "进入3");
synchronized (o1) {
System.out.println(Thread.currentThread().getName() + "进入4");
}
}
}
}
}
wait():当前线程暂停,并释放锁;
sleep()、yield():不会释放锁;