线程:线程在一个进程中负责代码的执行,是进程中一个执行路径 多线程:在一个进程中有多个线程同时在执行不同的任务 一个java应用程序至少有两个线程,一个是主线程负责main方法代码的执行,一个是垃圾回收器线程,负责了回收垃圾。
创建线程的两个方式:
【方式一】:
public class test extends Thread {
@Override //把自定义线程的任务代码写在run方法中。
public void run() {
for(int i = 0 ; i < 100 ; i++){
System.out.println("自定义线程:"+i);
}
}
public static void main(String[] args) {
//创建了自定义的线程对象。
test thread = new test();
//调用start方法启动线程
thread.start();
for(int i = 0 ; i < 100 ; i++){
System.out.println("main线程:"+i);
}
}
}
class TalkThread extends Thread{
@Override
public void run() {
while(true){
System.out.println("语音聊天");
}
}
}
class VideoThread extends Thread{
@Override
public void run() {
while(true){
System.out.println("播放视频");
}
}
}
public class test {
public static void main(String[] args) {
// 语音聊天与视频聊天
TalkThread talkThread = new TalkThread();
talkThread.start();
VideoThread videoThread = new VideoThread();
videoThread.start();
}
}
方法 ----Thread(String name) 初始化线程的名字 ----setName(String name) 设置线程对象名 ----getName() 返回线程的名字 ----sleep() 线程睡眠指定的毫秒数( 静态方法) ----currentThread() 返回当前的线程对象(静态方法) ----getPriority() 返回当前线程对象的优先级,默认线程的优先级是5 ----setPriority(int newPriority) 设置线程的优先级,虽然设置了线程的优先级,但是具体的实现取决于底层的操作系统的实现(最大的优先级是10,最小的1,默认是5)
public class test extends Thread {
public test(String name){
super(name); //调用了Thread类的一个参数的构造方法。
}
@Override
public void run() {
System.out.println("this:"+ this);
System.out.println("当前线程对象:" + Thread.currentThread());
for (int i = 0; i < 30 ; i++) {
//sunshine:x
System.out.println(Thread.currentThread().getName()+":"+i);
//Thread类的run方法没有抛出异常类型,所以子类不能抛出异常类型,只能捕获
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
//创建了一个线程对象
test d = new test("sunshine");
//设置线程的优先级, 优先级的数字越大,优先级越高,优先级的范围是1~10
d.setPriority(10);
d.start();
for (int i = 0; i < 30 ; i++) {
// main:x
System.out.println(Thread.currentThread().getName()+":"+i);
}
System.out.println("自定义线程的优先级:"+d.getPriority()); //线程的优先级默认是5
System.out.println("主线程的优先级:"+Thread.currentThread().getPriority());
Thread mainThread = Thread.currentThread();
System.out.println("主线程的名字:"+ mainThread.getName());
}
}
【方式二】(推荐):
注意:Runnable实现类的对象并不是一个线程对象,只是实现了Runnable接口的对象而已。只有是Thread或者是Thread的子类才是线程对象。把Runnable实现类的对象作为实参传递给Thread对象,作用就是把Runnable实现类的对象的run方法作为了线程的任务代码去执行了。 推荐使用第二种实现Runnable接口的方法,因为java单继承,多实现的。
public class test implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
public static void main(String[] args) {
// 创建Runnable实现类的对象
test d = new test();
// 创建Thread类的对象, 把Runnable实现类对象作为实参传递
Thread thread1 = new Thread(d, "sunshine1"); // Thread类使用Target变量记录了d对象
Thread thread2 = new Thread(d, "sunshine2"); // Thread类使用Target变量记录了d对象
Thread thread3 = new Thread(d, "sunshine3"); // Thread类使用Target变量记录了d对象,
// 调用thread对象的start方法开启线程
thread1.start();
thread2.start();
thread3.start();
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
sun提供了线程同步机制
synchronized(锁对象){
需要被同步的代码...
}
注意事项:
同步函数就是使用synchronized修饰一个函数。
注意事项 :
原因:
class SaleTicket extends Thread{
//票数,静态成员变量
static int num = 50;
// static Object o = new Object();
public SaleTicket(String name) {
super(name);
}
@Override
public void run() {
while(true){
//同步代码块
synchronized ("锁") {
if(num>0){
System.out.println(Thread.currentThread().getName()+"售出了第csxiaoyao.com"+num+"号票");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
num--;
}else{
System.out.println("售罄了..");
break;
}
}
}
}
}
public class test {
public static void main(String[] args) {
//创建三个线程对象,模拟三个窗口
SaleTicket thread1 = new SaleTicket("窗口1");
SaleTicket thread2 = new SaleTicket("窗口2");
SaleTicket thread3 = new SaleTicket("窗口3");
//开启线程售票
thread1.start();
thread2.start();
thread3.start();
}
}
原因:
解决方案:尽量避免发生
一个线程完成任务时,要通知另一个线程去完成另一个任务
【生产者与消费者问题】 ----wait(): 等待,如果线程执行了wait方法,那么该线程会进入等待的状态,等待状态下的线程必须要被其他线程调用notify方法才能唤醒。 ----notify(): 唤醒,唤醒线程池等待线程其中的一个。 ----notifyAll(): 唤醒线程池所有等待线程。
wait与notify方法要注意的事项:
//产品类
class Product {
String name; // 名字
double price; // 价格
boolean flag = false; // 产品是否生产完毕的标识,默认情况是没有生产完成。
}
// 生产者
class Producer extends Thread {
Product p; // 产品
public Producer(Product p) {
this.p = p;
}
@Override
public void run() {
int i = 0;
while (true) {
synchronized (p) {
if (p.flag == false) {
if (i % 2 == 0) {
p.name = "苹果";
p.price = 6.5;
} else {
p.name = "香蕉";
p.price = 2.0;
}
System.out.println("生产者生产出了:" + p.name + " 价格是:" + p.price);
p.flag = true;
i++;
p.notifyAll(); // 唤醒消费者去消费
} else {
// 已经生产 完毕,等待消费者先去消费
try {
p.wait(); // 生产者等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
// 消费者
class Customer extends Thread {
Product p;
public Customer(Product p) {
this.p = p;
}
@Override
public void run() {
while (true) {
synchronized (p) {
if (p.flag == true) { // 产品已经生产完毕
System.out.println("消费者消费了" + p.name + " 价格:" + p.price);
p.flag = false;
p.notifyAll(); // 唤醒生产者去生产
} else {
// 产品还没有生产,应该 等待生产者先生产。
try {
p.wait(); // 消费者也等待了...
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
public class test {
public static void main(String[] args) {
Product p = new Product(); // 产品
// 创建生产对象
Producer producer = new Producer(p);
// 创建消费者
Customer customer = new Customer(p);
// 调用start方法开启线程
producer.start();
customer.start();
}
}
public class test extends Thread {
boolean flag = true;//标识符
public test(String name) {
super(name);
}
//同步函数
@Override
public synchronized void run() {
int i = 0;
while (flag) {
try {
this.wait(); // 等待..
} catch (InterruptedException e) {
System.out.println("出现异常..");
}
System.out.println(Thread.currentThread().getName() + ":" + i);
i++;
}
}
public static void main(String[] args) {
test d = new test("sunshine");
d.setPriority(10);
d.start();
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
// 当主线程的i是80的时候停止sunshine线程。
if (i == 80) {
d.flag = false;
// 方法一:把线程的等待状态强制清除,被清除状态的线程会接收到一个InterruptedException,停止
d.interrupt();
// 方法二:修改标志位,并唤醒进程
// synchronized (d) {
// d.notify(); //唤醒后状态位为false,停止
// }
}
}
}
}
在一个进程中如果只剩下了守护线程,那么守护线程也会死亡。 一个线程默认都不是守护线程。
//模拟下载更新包
public class test extends Thread {
public test(String name){
super(name);
}
@Override
public void run() {
for(int i = 1 ; i<=100 ; i++){
System.out.println("更新包目前下载"+i+"%");
if(i==100){
System.out.println("更新包下载完毕,准备安装..");
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
test d = new test("后台线程");
d.setDaemon(true); // setDaemon() 设置线程是否为守护线程,true为守护线程, false为非守护线程。
System.out.println("是守护线程吗?" + d.isDaemon()); // 判断线程是否为守护线程。
d.start();
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
加入
class Mon extends Thread{
public void run() {
System.out.println("妈妈洗菜");
System.out.println("妈妈切菜");
System.out.println("妈妈准备炒菜,发现没有酱油了..");
//叫儿子去打酱油
Son s= new Son();
s.start();
try {
s.join(); //加入。 一个线程如果执行join语句,那么就有新的线程加入,执行该语句的线程必须要让步给新加入的线程先完成任务,然后才能继续执行。
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("妈妈继续炒菜");
System.out.println("全家一起吃饭..");
}
}
class Son extends Thread{
csxiaoyao.com @Override
public void run() {
System.out.println("儿子下楼..");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("儿子一直往前走");
System.out.println("儿子打完酱油了");
System.out.println("上楼,把酱油给老妈");
}
}
public class test {
public static void main(String[] args) {
Mon m = new Mon();
m.start();
}
}