Java 多线程(Thread) 您所在的位置:网站首页 java中关于线程说法错误的是什么 Java 多线程(Thread)

Java 多线程(Thread)

2024-07-18 03:58| 来源: 网络整理| 查看: 265

实现多线程

 

 

一、实现多线程方案一:继承Thread类

步骤

步骤: 

    A:自定义类MyThread继承Thread类。     B:MyThread类里面重写run()。(为了区分哪些代码能够被线程执行,java提供了Thread类中的run()用来包含那些被线程执行的代码)     C:创建对象     D:启动线程

 

多线程:一个应用程序有多条执行路径 进程:正在执行的应用程序线程:进程的执行单元,执行路径单线程:一个应用程序只有一条执行路径多线程:一个应用程序有多条执行路径   

多进程的意义: 提高CPU的使用率 多线程的意义: 提高应用程序的使用率

 

1、多线程的执行流程图解 :

 

2、线程调度和获取设置线程优先级:

* 如何获取线程对象的优先级? * public final int getPriority():返回线程对象的优先级 * 如何设置线程对象的优先级呢? * public final void setPriority(int newPriority):更改线程的优先级。 * * 注意: * 线程默认优先级是5。 * 线程优先级的范围是:1-10。 * 线程优先级高仅仅表示线程获取的 CPU时间片的几率高,但是要在次数比较多,或者多次运行的时候才能看到比较好的效果。 * * IllegalArgumentException:非法参数异常。 * 抛出的异常表明向方法传递了一个不合法或不正确的参数。 public class ThreadPriority extends Thread { // 重写run方法 @Override public void run() { for (int x = 0; x < 100; x++) { System.out.println(getName() + ":" + x); } } } public class ThreadPriorityDemo { public static void main(String[] args) { ThreadPriority tp1 = new ThreadPriority(); ThreadPriority tp2 = new ThreadPriority(); ThreadPriority tp3 = new ThreadPriority(); tp1.setName("东方不败"); tp2.setName("岳不群"); tp3.setName("林平之"); //设置正确的线程优先级 tp1.setPriority(10); tp2.setPriority(1); tp1.start(); tp2.start(); tp3.start(); } }

 

线程控制

线程优先级:

1、线程控制--休眠线程:

 public static void sleep(long millis) public class ThreadSleep extends Thread { // 重写run方法 @Override public void run() { for (int x = 0; x < 100; x++) { System.out.println(getName() + ":" + x + ",日期:" + new Date()); // 睡眠 // 困了,我稍微休息1秒钟 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } public class ThreadSleepDemo { public static void main(String[] args) { ThreadSleep ts1 = new ThreadSleep(); ThreadSleep ts2 = new ThreadSleep(); ThreadSleep ts3 = new ThreadSleep(); ts1.setName("林青霞"); ts2.setName("林志玲"); ts3.setName("林志颖"); ts1.start(); ts2.start(); ts3.start(); } }

 

2、线程控制--加入线程:

public final void join():等待该线程终止

public class ThreadJoin extends Thread { // 重写run方法 @Override public void run() { for (int x = 0; x < 100; x++) { System.out.println(getName() + ":" + x); } } } public class ThreadJoinDemo { public static void main(String[] args) { ThreadJoin tj1 = new ThreadJoin(); ThreadJoin tj2 = new ThreadJoin(); ThreadJoin tj3 = new ThreadJoin(); tj1.setName("李渊"); tj2.setName("李世民"); tj3.setName("李元霸"); tj1.start(); try { tj1.join(); } catch (InterruptedException e) { e.printStackTrace(); } tj2.start(); tj3.start(); } }

 

3、线程控制--礼让线程:

public static void yield():暂停当前正在执行的线程对象,并执行其他线程

让多个线程的执行更和谐,但是不能靠它保证一人一次。

注:延申知识点:多线程 等待唤醒机制

public class ThreadYield extends Thread { // 重写run方法 @Override public void run() { for (int x = 0; x < 100; x++) { System.out.println(getName() + ":" + x); Thread.yield(); } } } public class ThreadYieldDemo { public static void main(String[] args) { ThreadYield ty1 = new ThreadYield(); ThreadYield ty2 = new ThreadYield(); ty1.setName("林青霞"); ty2.setName("刘意"); ty1.start(); ty2.start(); } }

 

4、线程控制--后台线程:

public final void setDaemon(boolean on):将该线程标记为守护线程或用户线程

当正在运行的线程都是守护线程时,Java 虚拟机退出。 该方法必须在启动线程前调用。

public class ThreadDaemon extends Thread { // 重写run方法 @Override public void run() { for (int x = 0; x < 100; x++) { System.out.println(getName() + ":" + x); } } } public class ThreadDaemonDemo { public static void main(String[] args) { ThreadDaemon td1 = new ThreadDaemon(); ThreadDaemon td2 = new ThreadDaemon(); td1.setName("关羽"); td2.setName("张飞"); // 设置守护线程 td1.setDaemon(true); td2.setDaemon(true); td1.start(); td2.start(); Thread.currentThread().setName("刘备"); for (int x = 0; x < 5; x++) { System.out.println(Thread.currentThread().getName() + ":" + x); } } }

 

5、线程控制--中断线程:

public void interrupt():中断线程。 把线程的状态终止,并抛出一个InterruptedException

public class ThreadStop extends Thread { // 重写run方法 @Override public void run() { System.out.println("开始执行:" + new Date()); // 我要休息10秒钟,亲,不要打扰我哦 try { Thread.sleep(10000); } catch (InterruptedException e) { // e.printStackTrace(); System.out.println("线程被终止了"); } System.out.println("结束执行:" + new Date()); } } public class ThreadStopDemo { public static void main(String[] args) { ThreadStop ts = new ThreadStop(); ts.start(); // 你超过三秒不醒过来,我就干死你 try { Thread.sleep(3000); // ts.stop(); ts.interrupt(); } catch (InterruptedException e) { e.printStackTrace(); } } }

 

线程的生命周期:

新建 -- 就绪 -- 运行 -- 死亡

 

二、多线程的实现方案2:实现Runnable接口(推荐使用)

步骤:     A:自定义类MyRunnable实现Runnable接口     B:重写run()方法     C:创建MyRunnable类的对象     D:创建Thread类的对象,并把C步骤的对象作为构造参数传递

public class MyRunnable implements Runnable { // 重写run方法 @Override public void run() { for (int x = 0; x < 100; x++) { // 由于实现接口的方式就不能直接使用Thread类的方法了,但是可以间接的使用 System.out.println(Thread.currentThread().getName() + ":" + x); } } } public class MyRunnableDemo { public static void main(String[] args) { // 创建MyRunnable类的对象 MyRunnable my = new MyRunnable(); // 创建Thread类的对象,并把C步骤的对象作为构造参数传递 // Thread(Runnable target) // Thread t1 = new Thread(my); // Thread t2 = new Thread(my); // t1.setName("林青霞"); // t2.setName("刘意"); // Thread(Runnable target, String name) Thread t1 = new Thread(my, "林青霞"); Thread t2 = new Thread(my, "刘意"); t1.start(); t2.start(); } }

(注):如果一个参数要的是接口,那么这里要的就是子类对象。

 

如何解决线程安全问题:

导致出问题的原因:(而且这些原因也是以后我们判断一个程序是否会有线程安全问题的标准)

是否是多线程环境是否有共享数据是否有多条语句操作共享数据 * 思想: * 把多条语句操作共享数据的代码给包成一个整体,让某个线程在执行的时候,别人不能来执行。 * 问题是我们不知道怎么包啊?其实我也不知道,但是Java给我们提供了:同步机制。 * * 同步代码块: * synchronized(对象){ * 需要同步的代码; * } * * A:对象是什么呢? * 我们可以随便创建一个对象试试。 * B:需要同步的代码是哪些呢? * 把多条语句操作共享数据的代码的部分给包起来 * * 注意: * 同步可以解决安全问题的根本原因就在那个对象上。该对象如同锁的功能。 * 多个线程必须是同一把锁。

 

案例:三个售票窗口出售总计100张的电影票

/* * A:同步代码块的锁对象是谁呢? * 任意对象。 * * B:同步方法的格式及锁对象问题? * 把同步关键字加在方法上。 * * 同步方法是谁呢? * this * * C:静态方法及锁对象问题? * 静态方法的锁对象是谁呢? * 类的字节码文件对象。(反射部分讲) */ public class SellTicketDemo { public static void main(String[] args) { // 创建资源对象 SellTicket st = new SellTicket(); // 创建三个线程对象 Thread t1 = new Thread(st, "窗口1"); Thread t2 = new Thread(st, "窗口2"); Thread t3 = new Thread(st, "窗口3"); // 启动线程 t1.start(); t2.start(); t3.start(); } } public class SellTicket implements Runnable { // 定义100张票 private static int tickets = 100; // 定义同一把锁 private Object obj = new Object(); private Demo d = new Demo(); private int x = 0; //同步代码块用obj做锁 // @Override // public void run() { // while (true) { // synchronized (obj) { // if (tickets > 0) { // try { // Thread.sleep(100); // } catch (InterruptedException e) { // e.printStackTrace(); // } // System.out.println(Thread.currentThread().getName() // + "正在出售第" + (tickets--) + "张票 "); // } // } // } // } //同步代码块用任意对象做锁 @Override public void run() { while (true) { if(x%2==0){ synchronized (SellTicket.class) { if (tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "张票 "); } } }else { sellTicket(); } x++; } } private static synchronized void sellTicket() { if (tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "张票 "); } } } class Demo { }

 

线程安全的类: StringBuffer sb = new StringBuffer();Vector v = new Vector();Hashtable h = new Hashtable() // Vector是线程安全的时候才去考虑使用的,但是我还说过即使要安全,我也不用你 // 那么到底用谁呢? // public static List synchronizedList(List list) List list1 = new ArrayList();// 线程不安全 List list2 = Collections .synchronizedList(new ArrayList()); // 线程安全

 

线程的状态转换图及常见执行情况:

状态转换图:

新建 -- 就绪 -- 运行 -- 阻塞 -- 就绪 -- 运行 -- 死亡

 

线程池(Thread pool):

可以执行Runnable和Callable对象

线程池的好处:线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。

/* 如何实现线程的代码呢? * A:创建一个线程池对象,控制要创建几个线程对象。 * public static ExecutorService newFixedThreadPool(int nThreads) * B:这种线程池的线程可以执行: * 可以执行Runnable对象或者Callable对象代表的线程 * 做一个类实现Runnable接口。 * C:调用如下方法即可 * Future submit(Runnable task) * Future submit(Callable task) * D:我就要结束,可以吗? * 可以。 */

 

1、实现案例(线程池的简单应用)--  Runnable:

public class MyRunnable implements Runnable { @Override public void run() { for (int x = 0; x < 100; x++) { System.out.println(Thread.currentThread().getName() + ":" + x); } } } public class ExecutorsDemo { public static void main(String[] args) { // 创建一个线程池对象,控制要创建几个线程对象。 // public static ExecutorService newFixedThreadPool(int nThreads) // 表示我要造2个线程 ExecutorService pool = Executors.newFixedThreadPool(2); // 可以执行Runnable对象或者Callable对象代表的线程 pool.submit(new MyRunnable()); pool.submit(new MyRunnable()); //结束线程池 pool.shutdown(); } }

2、实现案例(线程池的简单应用)--  Callable:

注:Callable是依赖线程池存在的

* 多线程实现的方式3: * A:创建一个线程池对象,控制要创建几个线程对象。 * public static ExecutorService newFixedThreadPool(int nThreads) * B:这种线程池的线程可以执行: * 可以执行Runnable对象或者Callable对象代表的线程 * 做一个类实现Runnable接口。 * C:调用如下方法即可 * Future submit(Runnable task) * Future submit(Callable task) * D:我就要结束,可以吗? * 可以。

 案例A:

//Callable:是带泛型的接口。 //这里指定的泛型其实是call()方法的返回值类型。 public class MyCallable implements Callable { @Override public Object call() throws Exception { for (int x = 0; x < 100; x++) { System.out.println(Thread.currentThread().getName() + ":" + x); } return null; } } public class CallableDemo { public static void main(String[] args) { //创建线程池对象 ExecutorService pool = Executors.newFixedThreadPool(2); //可以执行Runnable对象或者Callable对象代表的线程 pool.submit(new MyCallable()); pool.submit(new MyCallable()); //结束 pool.shutdown(); } }

 

 匿名内部类的方式实现多继承(便捷):

/* * 匿名内部类的格式: * new 类名或者接口名() { * 重写方法; * }; * 本质:是该类或者接口的子类对象。 */ public class ThreadDemo { public static void main(String[] args) { // 继承Thread类来实现多线程 new Thread() { public void run() { for (int x = 0; x < 100; x++) { System.out.println(Thread.currentThread().getName() + ":" + x); } } }.start(); // 实现Runnable接口来实现多线程 new Thread(new Runnable() { @Override public void run() { for (int x = 0; x < 100; x++) { System.out.println(Thread.currentThread().getName() + ":" + x); } } }) { }.start(); // 更有难度的(面试可能出现) new Thread(new Runnable() { @Override public void run() { for (int x = 0; x < 100; x++) { System.out.println("hello" + ":" + x); } } }) { public void run() { //真正运行的时候走的是它 for (int x = 0; x < 100; x++) { System.out.println("world" + ":" + x); } } }.start(); } }

 共勉:明日复明日,明日何其多。我生待明日,万事成蹉跎。 



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

      专题文章
        CopyRight 2018-2019 实验室设备网 版权所有