进程与线程
1.进程与线程的概念
1.进程 操作系统中程序的一次执行过程,是操作系统资源分配的最小单元。操作系统为每个进程分配独立的内存 进程是独立的
2.线程 线程在进程中的一个子任务,是操作系统任务分配的最小单元,在一个进程中的所有线程共享线程资源。 每个子任务对应一个线程
3.进程与线程关系
1.进程是操作系统资源分配的最小单元,线程是操作系统任务分配的最小单元.
2.进程的启动与销毁开销较大,与此相比,启动与销毁一个线程开销小的多.
3.进程间通信远比线程间通信复杂的多。
高并发:在同一时刻,并发访问的线程数量非常高(12306、淘宝) 加载:服务器内存不够 等待其他线程退出 DDos :高并发漏洞
高可用:若干台机器的损坏不能影响其他服务器
分布式:一个程序同时部署在多台机器上
2.java中多线程实现 java.long.Thread
此类是java中多线程的核心类 创建线程方法: a.自定义类继承Thread类,而后覆写run方法(run()放线程任务),然后调用start
package ThreadTest.MyThread;
public class TestDemo {
public static void main(String[] args) {
new myThread().start();
new myThread().start();
new myThread().start();
}
}
class myThread extends Thread{
private int ticket =10;
public void run(){
while(this.ticket>0){
System.out.println("剩余票数"+this.ticket--);
}
}
}
启动线程:调用 start(Thread类的方法) start() 线程的启动一律使用此方法 一个线程start()方法只能被调用一次,执行多次会抛出IllegalThreadStateExceptiom异常 b.实现Runnable接口然后覆写 run方法 Thread可以接收一个Runnable的对象(通过构造方法) 因为Thread类本身也实现了Runnable接口,与用户自定义的线程类共同组成代理设计模式 其中Thread类实现辅助操作,包括线程的资源调度等任务;自定义线程类完成真实任务。
package ThreadClass; public class Class { public static void main(String[] args) { MyThread myThread = new MyThread(); Thread thread1= new Thread(myThread); Thread thread2= new Thread(myThread); Thread thread3= new Thread(myThread); thread1.start(); thread2.start(); thread3.start(); } }
class MyThread implements Runnable {
private int ticket = 20;
@Override
public void run() {
while (ticket > 0) {
System.out.println("当前线程为" + Thread.currentThread().getName() + "还剩" + ticket-- + "票");
}
}
}
> public interface RunnableRunnable接口应由任何类实现,其实例将由线程执行。 > 该类必须定义一个无参数的方法,称为run 。 该接口旨在为希望在活动时执行代码的对象提供一个通用协议。 例如, > Runnable由Thread类Thread 。 活跃的只是意味着一个线程已经启动,还没有被停止。 > > 另外, Runnable提供了一个类被激活而不是Thread Thread类化的Thread 。 > 一个实现类Runnable可以在不继承运行Thread实例化一个Thread实例,并在传递本身作为目标。 在大多数情况下, > Runnable接口应使用,如果你只打算重写run()方法并没有其他Thread方法。 > 这是重要的,因为类不应该被子类化,除非程序员打算修改或增强类的基本行为。
继承Thread类与实现Runnable接口的区别
1.继承Thread类有单继承局限,相对而言实现Runnable接口更加灵活。并且Thread类本身也实现了Runnable接口,辅助真实线程类。
2.实现Runnable接口可以更好的实现程序共享的概念(Thread类也可以,稍微麻烦点)
c:实现Callable接口,而后覆写call 方法 V call() throws Exception; 线程执行任务后有返回值 Future接口:接收Callable接口的返回值 V get():接收Callable方法 产生callable对象, 产生FutureTask对象,可以接收callable对象 将FutureTask 作为参数传入 Thread中 1)定义一个真实的线程类实现Callable接口,覆写call()方法,真实线程类实例化 2)有一个Thread类的实例化对象类 start()启动线程 3)有一个FutureTask对象 Thread没有构造方法可以传入Callable对象,所以涉及Future和Runnable的共同间接子类FutureTask对象 它调用Future的 get()方法可以接收Callable的返回值。然后把FutureTask对象(Runnable子类)传给Thread对 象
package ThreadClass; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; public class CallThrad { public static void main(String[] args) throws ExecutionException, InterruptedException { FutureTask<String> task = new FutureTask<>(new MycallThread()); new Thread(task).start(); new Thread(task).start(); System.out.println(task.get()); } } class MycallThread implements Callable<String>{ private int ticket =20; public String call(){ while (ticket>0){ System.out.println("剩余票数:"+ticket--); } return "没了!"; } }
3. java中常用线程操作方法
取得当前JVM中正在执行的线程对象
public static native Thread currentThread()
###3.1 线程名称的命名与取得
3.1.1 线程命名
public Thread(Runable target,String name)//构造方法
public final synchronized void setName(String name)
3.1.2取得名称
String getName()
Thread.currentThread().getName();
3.2 线程休眠 sleep()
3.2.1定义:
public static native void sleep(long mills) throws InterruptedException
让线程暂缓执行,等到了预计时间之后再恢复执行 单位为ms
sleep方法会让当前线程立即交出CPU,但不会释放对象锁
3.2.2 代码实现
package ThreadTest.SleepTest; public class sleepDemo { public static void main(String[] args) { ThreadDemo threadDemo =new ThreadDemo(); new Thread(threadDemo).start(); new Thread(threadDemo).start(); new Thread(threadDemo).start(); } } class ThreadDemo implements Runnable{ @Override public void run() { for(int i=0;i<1000;i++){ try{ Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("当前线程"+Thread.currentThread().getName()+",i="+i); } } }
3.3 线程让步
yield() 暂停当前正在执行的线程对象,并执行其他线程(只能让拥有相同优先级的线程获取CPU)。
调用此方法之后会让当前线程交出CPU,让CPU去执行其他线程,不会释放锁。
注意!!!:yield不能控制具体的交出CPU的时间,yield方法只能让拥有相同优先级的线程有获得CPU执行时间的机会 调用yield()方法并不会让线程进入阻塞状态,而是让线程重回就绪状态,它只需要等待重新获取CPU执行时间。
3.3.1 定义
public native static yield()//同样不会释放锁
3.3.2 代码实现
package ThreadTest.yieldTest; public class yieldDemo { public static void main(String[] args) { mynewThread mynewThread1 =new mynewThread(); new Thread(mynewThread1).start(); new Thread(mynewThread1).start(); new Thread(mynewThread1).start(); } } class mynewThread implements Runnable{ @Override public void run() { for(int i=0;i<3;i++){ Thread.yield(); System.out.println("当前线程为"+Thread.currentThread().getName()+",i="+i); } } }
3.4 线程等待 join()
3.4.1 定义
等待线程终止 如果主线程中调用该方法时就会让主线程休眠,让调用该方法的线程run方法先执行,完毕之后再开始执行主线程
public final void ioin() throws InterruptedException
若一个线程1需要等到另一个线程2执行完毕后再恢复执行,可以在线程1中调用线程2的join()
在哪个线程中调用,哪个线程阻塞,等待线程执行完毕再恢复执行
从运行态到阻塞态,会释放锁
package ThreadTest.joinTest; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; public class joinDemo { public static void main(String[] args) throws InterruptedException { myThread mythread = new myThread(); Thread thread = new Thread(mythread,"子线程A"); thread.start(); System.out.println(Thread.currentThread().getName()); //主线程调用线程等待 thread.join(); System.out.println("代码结束"); } public static void printTime(){ Date date = new Date(); DateFormat format = new SimpleDateFormat("yyyy-mm-dd hh:mm:ss"); String time = format.format(date); System.out.println(time); } } class myThread implements Runnable{ @Override public void run() { try{ System.out.println("主线程睡眠前时间"); joinDemo.printTime(); Thread.sleep(2000); System.out.println(Thread.currentThread().getName()); System.out.println("睡眠时间结束"); joinDemo.printTime(); } catch (InterruptedException e) { e.printStackTrace(); } } }
3.5 线程停止
3.5.1 线程停止的三种方法:
1)设置标志位;(无法处理线程阻塞时停止问题)
线程中设置boolean类型的标志位,(flag,利用set方法在线程外,休眠一段时间后关闭线程);
package ThreadTest.FlagTest; public class FlagTestDemo { public static void main(String[] args) throws InterruptedException { MyThread myThread = new MyThread(); Thread thread1= new Thread(myThread,"子线程A"); thread1.start(); Thread.sleep(2000); myThread.setFlag(false); System.out.println("program over"); } } class MyThread implements Runnable{ //定义标记类 private boolean flag =true; @Override public void run() { int i=1; while(flag){ try { Thread.sleep(1000); System.out.println("第"+i+"次执行,线程名称为"+Thread.currentThread().getName()); i++; } catch (InterruptedException e) { e.printStackTrace(); } } } //设置标记 public void setFlag(boolean flag){ this.flag=flag; } }
2)**调用Thread提供的stoop()方法,强行关闭线程;(无论是否执行完,都关闭线程,后面的程序不再执行。本方法不推荐使用,因为会产生不完整数据);
stop会解除由线程获取的所有锁定,当在一个线程对象上调用stop()方法时,这个线程对象所运行的线程就会理解停止,如果这是线程中正在进行赋值操作,这样会产生不完整的残存数据。
3)**通过调用Thread提供的interrupt()方法
package ThreadTest.interruptTest; public class InterruptDemo { public static void main(String[] args) throws InterruptedException { MyThread myThread = new MyThread(); Thread thread1= new Thread(myThread,"子线程A"); thread1.start(); Thread.sleep(3000); //掉用interrupt()设置中断标志 thread1.interrupt(); System.out.println("代码结束!"); } } class MyThread implements Runnable{ private boolean flag =true; @Override public void run() { int i=1; while (flag){ try { Thread.sleep(1000);//阻塞之后 //currentThread()取得当前执行的线程对象 boolean bool = Thread.currentThread().isInterrupted(); //清除中断,抛出异常 if(bool){ System.out.println("非阻塞情况下执行该操作。。。线程状态"+bool); break; } System.out.println("第"+i+"次执行,线程名称为:"+Thread.currentThread().getName()); i++; } catch (InterruptedException e) { System.out.println("退出了"); boolean bool = Thread.currentThread().isInterrupted(); System.out.println(bool); return; } } } public void setFlag(boolean flag){ this.flag=flag; } }
Thread中提供的isinterrupt()可以检测当前线程状态是否处于中断状态。
调用interrupt()方法会将状态置为true; 这个方法只会给线程设置一个为true的中断标志(中断标志只是一个boolean类型的变量),而设置之后,则根据线程当前的状态进行不同的后续操作。
如果线程处于非阻塞状态,那么仅仅是线程的中断标志被修改为true状态而已;如果线程处于阻塞状态,那么在将中断标志置为true之后,有以下操作
a,如果是wait、sleep、join三个方法引起的阻塞,那么会将线程的中断标志置为false,并抛出一个InterrputedEcxception;
b,如果在中断时,线程正处于非阻塞状态,则将中断标志修改为true,一旦进入阻塞状态,按照阻塞状态情况来处理。

浙公网安备 33010602011771号