程序:是一个指令的集合
进程:(正在执行中的程序),是一个静态的概念
线程:是进程中一个“单一的连续控制流程”,又被称为轻量级进程,,一个进程可拥有多个并行的线程
实现多线程的时候:
1、需要继承Thread类
2、需要重写run方法,指的是核心执行的逻辑
3、线程在启动的时候,不要直接调用run方法,而是要通过start()来进行调用
4、每次运行相同的代码,出来的结果可能不一样,原因在于多线程谁先抢占资源人为无法进行控制
public class ThreadDemo extends Thread {
@Override
public void run() {
for(int i = 0;i < 10;i ++){
System.out.println(Thread.currentThread().getName()+"------------"+i);
}
}
public static void main(String[] args) {
ThreadDemo threadDemo = new ThreadDemo();
threadDemo.start();
for(int i = 0;i < 5;i ++){
System.out.println(Thread.currentThread().getName()+"============="+i);
}
}
}
第二中实现方式:(使用了代理设计模式):
1、实现Runnable接口
2、重写run方法
3、创建Thread对象,将刚刚创建好的runnable的子类实现作为thread的构造参数
4、通过thread.start()进行启动
public class RunnableDemo implements Runnable {
@Override
public void run() {
for(int i = 0;i < 10;i ++){
System.out.println(Thread.currentThread().getName()+"------------"+i);
}
}
public static void main(String[] args) {
RunnableDemo runnableDemo = new RunnableDemo();
Thread thread = new Thread(runnableDemo);
thread.start();
for(int i = 0;i < 5;i ++){
System.out.println(Thread.currentThread().getName()+"============="+i);
}
}
}
线程的生命周期
1、新生状态:创建好当前线程对象后,没有启动之前(没有调用start()之前)
2、就绪状态:准备开始执行,并没有执行(调用start方法后)
当对应的线程创建万册换呢过且调用对应的start方法后,所有的线程还会添加到一个就绪队列中 ,所有线程同时去抢占CPU的资源
3、运行状态:当当前进程获取到CPU资源后,就绪队列中的所有线程会去抢占CPU的资源,谁先抢占到就谁先执行,执行的过程中成为运行状态
4、死亡状态:当运行中的线程正常执行完所有的代码逻辑或者因为异常情况导致程序结束叫做死亡状态
进入的方式:
1、正常运行完成且结束
2、人为中断执行,比如使用stop方法
3、程序抛出未捕获的异常
5、阻塞状态:在程序运行过程中,发生某些异常情况,导致当前线程无法再顺利执行下去,此时会进入阻塞状态,导致阻塞的愿意消除以后,所有的阻塞队列会再次进入就绪状态,随机抢占CPU资源,等待执行
进入的方法:
1、sleep方法
2、等待io资源
3、join方法(代码中执行的逻辑)
线程类api方法
//获取当前线程对象
Thread thread = Thread.currentThread();
//获取当前线程的名称
System.out.println(thread.getName());
//获取线程的id
System.out.println(thread.getId());
//获取线程的优先级,一般系统中范围是0-10的值(有些是0-100),如果没有经过设置的话,默认值是5
System.out.println(thread.getPriority());
//设置线程池的优先级
//优先级越高一定优先执行吗? 不一定,只是优先执行的概率比较大而已
thread.setPriority(10);
System.out.println(thread.getPriority());
//对当前线程进行强制阻断,让另一个线程优先执行
thread.join();
//休眠指定时间(单位为毫秒) 运行->阻塞
thread.sleep(1000);
/*当前正在执行的线程暂停一次(暂停后立即同其它线程一起抢占cpu资源),
不阻塞,允许其它线程执行,线程进入就绪状态,如果没有其它等待执行
的线程,这个时候当前线程就会马上恢复执行 运行-> 就绪*/
Thread.yield();
//强迫线程停止执行;
thread.stop();
注意:
在多线程的时候,可以实现唤醒和等待的过程,但是唤醒和等待操作的对象不是thread类,而是我们设置的共享对象或者共享变量
多线程并发访问的时候会出现数据安全的问题,解决的方法如下:
1、同步代码块:synchronized(共享资源、共享对象,需要是object的子类){具体执行的代码块}
public class TicketRunnable implements Runnable {
private int ticket = 5;
@Override
public void run() {
for(int i = 0;i < 100;i ++){
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (this){
if(ticket>0)
System.out.println(Thread.currentThread().getName()+"正在出售第"+(ticket--)+"张票");
}
}
}
public static void main(String[] args) {
TicketRunnable ticket = new TicketRunnable();
Thread t1 = new Thread(ticket,"A");
Thread t2 = new Thread(ticket,"B");
Thread t3 = new Thread(ticket,"C");
Thread t4 = new Thread(ticket,"D");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
2、将核心代码逻辑定义成一个方法,使用synchronized关键字进行修饰,此时不需要指定共享对象
public class TicketRunnable1 implements Runnable {
private int ticket = 5;
@Override
public void run() {
for(int i = 0;i < 100;i ++){
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.sale();
}
}
public synchronized void sale() {
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "正在出售第" + (ticket--) + "张票");
}
}
public static void main(String[] args) {
TicketRunnable1 ticket = new TicketRunnable1();
Thread t1 = new Thread(ticket,"A");
Thread t2 = new Thread(ticket,"B");
Thread t3 = new Thread(ticket,"C");
Thread t4 = new Thread(ticket,"D");
t1.start();
t2.start();
t3.start();
t4.start();
}
}