-
就是独立运行的一个程序, 是一个实体, 每个进程都有它自己的内存空间。
-
进程的状态
- 进程执行时的间断性,决定了进程可能具有多种状态。运行中的进程具有以下三种基本状态
-
- 就绪状态(Ready)
-
- 运行状态(Running)
-
- 阻塞状态(Blocked)
-
线程就是进程当中的一条执行路径,线程之间共享一个内存空间, 线程之间可以自由的切换, 并发执行。一个进程中可以多个线程,但是最少得有一个线程,
-
例子: 在电子厂流水线中, 一条流水线就表示一个进程, 而流水线上的人 就是线程, 也就是真正来组装产品的人, 在映射过来的话就是 线程就是真正来执行代码的。
-
并行: 当两个cpu核心运行两个任务得时候, 那么这个两个任务是同时运行,那么就是并行。(cpu核心数大于或等于运行任务数)
-
并发: 是指两个任务同时请求运行, 而处理器只有一个核心只能接收一个任务, 就会把两个任务轮流运行, 由于
处理器时间片(CPU运行该程序的时间)运行时间较短, 就感觉两个程序同时运行。
// 方法1: 继承Thread 类 class MyThread extends Thread { public void run() { // 当前线程要做的事情 for (int i = 0; i < 100; i++) { // Thread.currentThread() 获取当前线程实例 // .getName() 获取当前线程名字 System.out.println(Thread.currentThread().getName() + ":" + i); } } } // main // 创建线程 Thread t1 = new MyThread(); // 运行线程(先是就绪状态, 最终是JVM开启线程) t1.start();2) 实现Runnable 接口
// 方法2: 实现Runnable 接口 class MyRunnable implements Runnable { public void run() { // 当前线程要做的事情 for (int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName() + ":" + i); } } } // main // 创建实例(Running 接口,可以理解为一个任务) Runnable myRunnable = new MyThread(); // 通过Thread 类对Runnable进行包装(将任务添加到一个线程中) Thread t2 = new Thread(myRunnable); t2.start();(3) 线程休眠
// 放在哪个线程里面,就表示哪个线程要休眠 Thread.sleep(毫秒数);
- 一旦当前线程休眠,则会释放CPU时间片, 一旦释放CPU时间片, 则其他线程会进行争取这个世时间片。
- 加入线程, 让调用的线程先去执行指定的时间或者执行完毕。
- 如果没有给定时间,则表示将该线程执行完毕 等待该线程的死亡。
// 可以指定毫秒数 和纳秒数 thread.join()
public class ThreadDemo2 { // 主线程 public static void main(String[] args) { MyRunnable2 myRunnable2 = new MyRunnable2(); // 创建一个子线程 Thread t1 = new Thread(myRunnable2); t1.start(); for (int i = 0; i < 50; i++) { System.out.println(Thread.currentThread() + "--" + i); if (i == 20) { try { // 注意:此时主线程是阻塞的, 直到t1执行完毕 t1.join(); }catch (InterruptedException e) { e.printStackTrace(); } } } } } class MyRunnable2 implements Runnable { @Override public void run() { for (int i = 0; i < 50; i++) { System.out.println(Thread.currentThread().getName() + "--" + i); try { Thread.sleep(250); }catch (InterruptedException e) { e.printStackTrace(); } } } }(5) 线程的中断 1) 方法1 通过interrupt() 方法 来中断
public class InterruptDemo { public static void main(String[] args) { MyRunnable3 myRunnable3 = new MyRunnable3(); Thread t1 = new Thread(myRunnable3); t1.start(); for (int i = 0; i < 50; i++) { if (i == 20) { // 1. 中断t1线程 // 注意: 此时在线程中如果调用了sleep()方法 那么该方法会抛出了一个 InterruptedException 异常 t1.interrupt(); } } } } class MyRunnable3 implements Runnable { @Override public void run() { for (int i = 0; i < 50; i++) { System.out.println(Thread.currentThread().getName() + "--" + i); // 3. isInterrupte() 方法表示当前线程是否已经中断 if (Thread.currentThread().isInterrupted()) { break; }else { try { Thread.sleep(0); }catch (InterruptedException e) { e.printStackTrace(); // 2. 如果线程调用了interrupt方法, 则会在调用sleep方法处抛出InterruptedException异常 // 并且会自动去除线程中断异常, 一旦去除,则线程还是会运行。 所以interrpt() 方法只起到了标记的作用 // 所以需要在中断一次, 是为下一次循环判断 Thread.currentThread().interrupt(); } } } } }2) 方法2 自定义中断线程
public static void main(String[] args) { MyRunnable4 myRunnable4 = new MyRunnable4(); Thread t2 = new Thread(myRunnable4); t2.start(); for (int i = 0; i < 50; i++) { System.out.println(Thread.currentThread().getName() + "--" + i); try { Thread.sleep(250); } catch (InterruptedException e) { e.printStackTrace(); } if (i == 20) { // 2. 中断t1线程 myRunnable4.flag = false; } } } } class MyRunnable4 implements Runnable { // 1. 创建一个中断条件 public boolean flag = true; @Override public void run() { int i = 0; while (flag){ System.out.println(Thread.currentThread().getName() + "--" + (i++)); try { Thread.sleep(250); } catch (InterruptedException e) { e.printStackTrace(); } } } }(6) 线程的其他方法
-
setDaemon(boolean on) 可以设置为守护线程或用户线程
-
如果运行的线程都是守护线程,则JVM会退出
-
isDaemon() 判断是否是守护线程
-
getId() 返回该线程的标识符
-
getName() 获取 该线程的名字
-
**setName(String name) 设置该线程的名字 **
-
isAlive() 判断该线程是否为活动状态
-
setPriority(int newPriority) 更改该线程的优先级
- 优先级: 可以提高该线程抢到时间片的概率
static int MAX_PRIORITY // 线程可以具有的最高优先级。 static int MIN_PRIORITY // 线程可以具有的最低优先级。 static int NORM_PRIORITY // 分配给线程的默认优先级
-
在多线程 *** 作中, 多个线程同时可以处理同一个资源。
-
先看代码
public class SynchronizeDemo { public static void main(String[] args) { Ticket tk = new Ticket(); // 创建线程 Thread t1 = new Thread(tk); t1.setName("抢票机器1"); Thread t2 = new Thread(tk); t2.setName("抢票机器2"); // 开始抢票 t1.start(); t2.start(); } } // 售票 class Ticket implements Runnable{ private int currentTicket = 10; // 当前剩余票的数量 @Override public void run() { // 抢票 while (currentTicket > 0) { System.out.println(Thread.currentThread().getName()+"成功抢到票" + currentTicket--); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }2) 线程同步
-
线程同步就是为了解决数据共享问题, 所谓的同步就是 多个线程在同一时刻只能有一个线程执行指定代码,
其他线程必须等待该线程执行完毕后才可以执行。
// main() 方法不变 // 售票 class Ticket implements Runnable{ private int currentTicket = 10; // 当前剩余票的数量 // 随便定义一个对象 private final Object obj = new Object(); @Override public void run() { // 抢票 while (currentTicket > 0) { // 如果多个线程都在运行当前任务 最简单的可以直接使用 this 当前任务对象, 来当作同步锁 synchronized (obj) { System.out.println(Thread.currentThread().getName()+"成功抢到票" + currentTicket--); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }二、同步方法2(使用synchronized 修饰的方法)
- 使用这个方法使用锁对象是当前任务的实例,也就是this
// 售票 class Ticket implements Runnable{ private int currentTicket = 10; // 当前剩余票的数量 @Override public void run() { // 抢票 while (currentTicket > 0) { // 使用synchronized 修饰的方法 syncFun(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } // synchronized 修饰的方法 public synchronized void syncFun() { if (currentTicket > 0) { System.out.println(Thread.currentThread().getName()+"成功抢到票" + currentTicket--); } } }三、同步方法3(使用Lock互斥锁)
// 售票 class Ticket implements Runnable{ private int currentTicket = 10; // 当前剩余票的数量 private final Object obj = new Object(); // 创建一个互斥锁 private final Lock lock = new ReentrantLock(); @Override public void run() { // 抢票 while (currentTicket > 0) { // 加锁 lock.lock(); if (currentTicket > 0) { System.out.println(Thread.currentThread().getName()+"成功抢到票" + currentTicket--); } // 解锁 lock.unlock(); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } }四、生产者与消费者示例
- 这里我用两种队列实现的
class Food2 { private String name; private String desc; public Food2(String name) { this.name = name; } public Food2() { } public String getName() { return name; } @Override public String toString() { return "Food2{" + "name='" + name + ''' + ", desc='" + desc + ''' + '}'; } } public class ProductorAndConsumer2 { // 创建一个队列 private static final BlockingQueue2) 使用synchronized 和 linkedlist 队列q = new linkedBlockingQueue<>(); // 创建一个生产者 static class Productor implements Runnable { @Override public void run() { // 生产10道菜 for (int i = 0; i < 10; i++) { Food2 food2 = new Food2("红烧肉" + i); System.out.println("生产者:生产出一道" + food2.getName()); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } try { // 将这道菜添加到队列(类似于将菜放到了取菜口, 让用户取餐) q.put(food2); } catch (InterruptedException e) { e.printStackTrace(); } } } } // 创建一个消费者 static class Consumer implements Runnable { @Override public void run() { // 不停的消费 while (true) { // 这里写了一个死的 try { // 从队列中取数据(消费者到取餐口取餐,进行消费) Food2 food = q.take(); // 这个take方法, 如果队列中没有数据,则会阻塞 Thread.sleep(500); System.out.println("消费者:消费了一道" + food.getName()); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) { // 创建任务 Productor p = new Productor(); Consumer c = new Consumer(); // 创建线程 Thread t1 = new Thread(p); Thread t2 = new Thread(c); t1.start(); t2.start(); } } // 运行结果只 截取了一部分查看
public class ProductorAndConsumer2 { // 创建一个队列 private static final Queue3)总结q2 = new linkedList<>(); private static final int MAX_CAPACITY = 1; // 仓库最大容量 // 创建一个生产者 static class Productor implements Runnable { public void run() { synchronized (q2) { // 生产10道菜 for (int i = 0; i < 10; i++) { if (q2.size() == MAX_CAPACITY) { // 仓库已满 try { // 让当前线程等待 q2.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } Food2 food2 = new Food2("红烧肉" + i); System.out.println("生产者:生产出一道" + food2.getName()); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } // 将这道菜添加到队列(类似于将菜放到了取菜口, 让用户取餐) q2.add(food2); // 唤醒其他线程 q2.notify(); } } } } // 创建一个消费者 static class Consumer implements Runnable { @Override public void run() { // 不停的消费 while (true) { synchronized (q2) { if (q2.size() == 0) { try { // 当前线程等待 q2.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 从队列中取数据(消费者到取餐口取餐,进行消费) Food2 food = q2.poll(); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("消费者:消费了一道" + food.getName()); q2.notify(); // 唤醒其他线程 } } } } public static void main(String[] args) { // 创建任务 Productor p = new Productor(); Consumer c = new Consumer(); // 创建线程 Thread t1 = new Thread(p); Thread t2 = new Thread(c); t1.start(); t2.start(); } }
-
使代码块保持简短。把不随线程变化的预处理和后处理移出synchronized 块。
-
不要阻塞。如InputStream.read()。
-
在持有锁的时候,不要对其它对象调用方法。
-
如果同步过多可能会造成死锁
-
sleep 与 wait 的区别?
- sleep: 让线程进入休眠状态, 让出CPU时间片, 不释放对象的监视器的所有权(对象锁不会被释放)
- wait: 让线程进入等待状态, 让出CPU时间片, 释放对象监视器的所有权, 等待其他线程通过notify来唤醒
-
线程池是预先创建线程的一种技术, 线程池在任务五还没有到来之前, 创建一定数量的线程, 放入空闲队列中,
然后对这些线程进行复用, 减少频繁的创建和销毁对象。
-
在JDK1.5 以后提供了线程的线程池
-
Executor 是线程池的顶级接口
-
具体使用的是Executor 下的子接口 ExecutorService;
-
Executor 接口: 只有一个方法, 就是执行已经提交的Runnable任务对象
-
ExecutorService 接口: 提供了很多方法,来 *** 作先成功池
-
具体的实现类是Executors 类
-
它们都在java.util.concurrent 包下
-
下面展示两个比较常用的线程池做介绍, 其他线程池的使用都差不多
-
创建一个单线程线程池, 这个线程池只有一个线程工作, 也就是单线程串行执行所有任务(按顺序一个一个执行),
如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此 线程池保证所有任务的执行顺序按照任务的提交顺序执行。
-
代码
public class ExecutorDemo { public static void main(String[] args) { // 创建一个单线程的线程池 ExecutorService es = Executors.newSingleThreadExecutor(); // 让线程执行指定任务 es.execute(new MyRunnable7()); es.execute(new MyRunnable7()); // 终止线程池 es.shutdown(); } } class MyRunnable7 implements Runnable { @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println("run--" + i); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } } } }3) newFixedThreadPool 类 创建固定大小的线程池
-
创建固定大小的线程池。每次提交一个任务就创建一个线程,直 到线程达到线程池的最大大小。
如果某个线程因为执行异常而结束, 那么线程池会补充一个新线程。
-
代码
public static void main(String[] args) { // 创建一个指定线程数量的线程池 ExecutorService es = Executors.newFixedThreadPool(2); // 让线程执行指定任务 es.execute(new MyRunnable7()); es.execute(new MyRunnable7()); // 终止线程池 es.shutdown(); } class MyRunnable7 implements Runnable { @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println("run--" + i); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } } } }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)