多线程有关的知识

tech2024-07-11  59

1.4.1并发和并行

并行:指两个或多个事件在同一时刻发生(同时执行)

并发:指两个或多个事件在同一时间段内发生(交替执行)

1.4.2进程和线程

一.进程

进程(process)是指正在运行的程序。如QQ,是程序一次动态执行的过程。它对应了从代码加载、执行并执行完 毕的一个完整过程,这个过程也是进程本身从产生、发展到消亡的过程。操作系统同时管理一个计算机系统中的多个进程,让计算机系统中的多个进程轮流使用CPU资源,或者共享资源。

特点:

进程是系统运行的基本单位每一个进程都有自己独立的空间、一组系统资源每一个进程内部数据和状态都是完全独立的每一个应用程序运行时都会产生一个进程

二、线程

线程是进程中执行运算的最小单位,一个进程在其执行过程中可以产生多个线程,而线程必须在某个进程内执行。

线程是进程内部的一个执行单元,是完成一个独立任务的顺序控制流程。一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以叫做多线程程序。

三、进程和线程的区别

进程:有独立的内存空间,进程中的数据存放空间(栈空间和堆空间)是独立的,至少有一个线程。

线程:堆空间是共享的,占空间是独立的,线程消耗的资源比进程小得多

3.多线程和多进程的区别

本质的区别在于每个进程拥有自己的一套变量,而线程则是共享数据。线程之间共享数据是有风险的。然而共享变量使线程之间的通信比进程之间通信更有效,、更容易。此外,在有的操作系统中,与进程相比,线程更轻量级,创建、撤销一个线程比启动新的进程开销要小得多。

线程调度

1.分时调度:所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间

2.抢占式调度:优先让优先级高的线程使用cpu,如果线程的优先级相同,那么会随机选择一个(线程随机性),java使用的是抢占式调度

4.创建线程类

每个程序至少自动又有一个线程,称为主线程。当程序加载到内存时启动主线程。main方法是主线程的入口,运行java程序时会指向这个方法

常见一个新的执行线程有两种方法,一个是将类声明为Thread的子类。这个子类应该重写Thread的子类Run。然后就可以分配并启动Thread的子类。

一、使用Thread类

java.lang.Thread类代表线程。每个线程的作用是完成一定的任务,实际上就是执行一段程序流即一段顺序执行的代码。java使用线程执行体来代表这段程序流。

package cn.itlaobing.zeyu; public class MyThread extends Thread { public MyThread(String mythread) { super(mythread); } @Override public void run() { for (int i=0;i<200;i++){ System.out.println(getName()+":正在执行"+i); try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } } } package cn.itlaobing.zeyu; public class ThreadTest { public static void main(String[] args) throws InterruptedException { MyThread myThread = new MyThread("Mythread"); myThread.start(); for (int i=0;i<200;i++){ System.out.println("主线程--正在执行"+i); Thread.sleep(50); } } }

常用的构造方法:

public Thread()//分配一个线程对象 public Thread(String name)//分配一个指定名字的新的线程对象 public Thread(Runnable Target) //分配一个带有指定目标新的线程对象 public Thread(Runnable Target,String name) //分配一个带有指定目标新的线程对象,并指定名字

二、线程Thread的属性(Fields)

/**优先级 最小 * The minimum priority that a thread can have. */ public static final int MIN_PRIORITY = 1; /** 默认 * The default priority that is assigned to a thread. */ public static final int NORM_PRIORITY = 5; /** 最大 * The maximum priority that a thread can have. */ public static final int MAX_PRIORITY = 10;

三、线程Thread的常用方法

public static Thread currentThread() 返回对当前正在执行的线程对象的引用。 public void run() //如果这个线程是使用单独的Runnable运行对象构造的,则Runnable对象的run方法; //否则,此方法不执行任何操作并返回。 //Thread的Thread应该覆盖此方法。 public void start() //导致此线程开始执行; Java虚拟机调用此线程的run方法。 //结果是两个线程同时运行:当前线程(从调用返回到start方法)和另一个线程(执行其run方法)。 //不止一次启动线程是不合法的。 特别地,一旦线程完成执行就可能不会重新启动。 //IllegalThreadStateException - 如果线程已经启动。 public static native void sleep(long millis) /*使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行),具体取决于系统定时器和调度程序的精度和准确性。 线程不会丢失任何显示器的所有权。*/ public final String getName() //返回此线程的名称。 public final void setName(String name) //将此线程的名称更改为等于参数name 。 public final void setPriority(int newPriority) //更改此线程的优先级。 public final int getPriority() //返回此线程的优先级。 public final boolean isAlive() //测试这个线程是否活着。 如果一个线程已经启动并且尚未死亡,那么线程是活着的。 public final void join() //等待这个线程死亡。 //调用此方法的行为方式与调用完全相同 join (0) public final void join(long millis) //等待这个线程死亡的时间最多为millis毫秒。 0的超时意味着永远等待。 public static boolean interrupted() /*测试当前线程是否中断。 该方法可以清除线程的中断状态 。 换句话说,如果这个方法被连续调用两次,那么第二个调用将返回false(除非当前线程再次中断,在第一个调用已经清除其中断状态之后,在第二个调用之前已经检查过)。 忽略线程中断,因为线程在中断时不存在将被该方法返回false所反映。 */ public Thread.State getState() //返回此线程的状态。 该方法设计用于监视系统状态,不用于同步控制。

四、使用接口的方式创建

java.lang.Runnable 也是非常常见的一种创建线程的方式,我们只需要重写run方法即可。任何实现Runnable 的类,其实例都能被线程执行。

package cn.itlaobing.zeyu; public class RunnableTest implements Runnable { @Override public void run() { for (int i=0;i<500;i++){ System.out.println(Thread.currentThread().getName()+" "+i); } } } package cn.itlaobing.zeyu; public class ThreadTest { public static void main(String[] args) throws InterruptedException { // MyThread myThread = new MyThread("Mythread"); // myThread.start(); RunnableTest runnableTest = new RunnableTest(); Thread thread = new Thread(runnableTest); thread.start(); for (int i=0;i<500;i++){ System.out.println("主线程--正在执行"+i); } } }

五、Thread和Runnable区别

1.适合多个相同的程序代码的线程去共享同一个资源

2.可以避免java中的单继承的局现性

3.增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立

4.实现了Runnable接口的话,很容易的实现资源共享(一个实例多个线程运行)

5.线程池只能放入实现Runnable或callable类线程,不能直接放入继承Thread的类

5.线程安全问题

//电影院卖票问题 /* 测试类 */ package com.itlaobing.zeyu; public class TicketTest { public static void main(String[] args) { Ticket ticket = new Ticket(); Thread thread1 = new Thread(ticket,"窗口1"); Thread thread2 = new Thread(ticket,"窗口2"); Thread thread3 = new Thread(ticket,"窗口3"); thread1.start(); thread2.start(); thread3.start(); } } /* 方法一:同步代码块 */ package com.itlaobing.zeyu; public class Ticket implements Runnable { //电影票总数 private int tickets = 100; Object o = new Object(); @Override public void run() { while (true){ synchronized (o){ if (tickets>0){ try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } String name = Thread.currentThread().getName(); System.out.println("正在售卖第"+tickets--+"张票"); }else { break; } } } } } /* 方法二:同步方法 */ @Override public void run() { while (true){ sellTickets(); } } private synchronized void sellTickets() { if (tickets>0){ try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } String name = Thread.currentThread().getName(); System.out.println("正在售卖第"+tickets--+"张票"); } } /* 方法三锁机制 */ private Lock lock = new ReentrantLock();//重入锁 @Override public void run() { while (true){ lock.lock(); sellTickets(); lock.unlock(); } } private synchronized void sellTickets() { if (tickets>0){ try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } String name = Thread.currentThread().getName(); System.out.println(Thread.currentThread().getName()+"正在售卖第"+tickets--+"张票"); } }

6.生产者和消费者

/* 面包-- 制作,吃的方法 name-->面包的名字,用时间表示 cook对象只有一个,全程代码中只有这个对象的引用 */ package com.itlaobing.zeyu; import java.time.LocalDateTime; public class Cook { //面包 private String name; private Cook(){} private static Cook cook; public synchronized static Cook getInstance(){ if(cook==null){ cook = new Cook(); } return cook; } public synchronized void make() throws InterruptedException { if (name!=null){ wait(); } name = "豆沙包" + LocalDateTime.now().toString(); System.out.println(Thread.currentThread().getName()+"做了一个面包" + name); notifyAll(); } public synchronized void eat() throws InterruptedException { if (name==null){ wait(); eat(); return; } System.out.println(Thread.currentThread().getName()+"吃了一个:"+name); name = null; notifyAll(); } } -------------------------------------------------------------------------------------- /* 做面包的线程 */ package com.itlaobing.zeyu; public class MakeThread implements Runnable { private Cook cook; public MakeThread(Cook cook){ this.cook = cook; } @Override public void run() { while (true){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } try { cook.make(); } catch (InterruptedException e) { e.printStackTrace(); } } } } -------------------------------------------------------------------------------------- /* 吃面包的线程 */ package com.itlaobing.zeyu; public class EatThread implements Runnable { private Cook cook; public EatThread(Cook cook){ this.cook = cook; } @Override public void run() { while (true){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } try { cook.eat(); } catch (InterruptedException e) { e.printStackTrace(); } } } } ---------------------------------------------------------------------------------------- /* 测试类 */ package com.itlaobing.zeyu; public class CookTest { public static void main(String[] args) throws InterruptedException { Cook cook = Cook.getInstance(); MakeThread makeThread = new MakeThread(cook); EatThread eatThread = new EatThread(cook); Thread thread1 = new Thread(makeThread,"zeyu" ); Thread thread2 = new Thread(eatThread,"浪老师"); Thread thread3 = new Thread(eatThread,"红雨老师"); thread1.start(); thread2.start(); thread3.start(); // while (true){ // System.out.println("make="+thread1.getState()+",eat="+thread2.getState()+"和"+thread3.getState()); // Thread.sleep(1000); // } } }
最新回复(0)