进程与多线程

进程与多线程

1. 进程与线程的概念

1.进程

操作系统中程序的一次执行过程,是操作系统资源分配的最小单元。操作系统为每个进程分配独立的内存

进程是独立的

2.线程

线程在进程中的一个子任务,是操作系统任务分配的最小单元,在一个进程中的所有线程共享线程资源。

每个子任务对应一个线程

3.进程与线程关系

1.进程是操作系统资源分配的最小单元,线程是操作系统任务分配的最小单元.

2.进程的启动与销毁开销较大,与此相比,启动与销毁一个线程开销小的多.

3.进程间通信远比线程间通信复杂的多。

  • 高并发:在同一时刻,并发访问的线程数量非常高(12306、淘宝)

    ​ 加载:服务器内存不够 等待其他线程退出

    ​ DDos :高并发漏洞

  • 高可用:若干台机器的损坏不能影响其他服务器

  • 分布式:一个程序同时部署在多台机器上

2.java中多线程实现

java.long.Thread 此类是java中多线程的核心类

创建线程方法:

a.自定义类继承Thread类,而后覆写run方法(run()放线程任务),然后调用start

package ThreadTest.MyThread;
/**
 * @Name:
 * @Author:ZYJ
 * @Date:2019-05-28-22:33
 * @Description:
 */
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;
/**
 * @Name:
 * @Author:ZYJ
 * @Date:2019-05-21-19:30
 * @Description:
 */
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对象

它调用Futureget()方法可以接收Callable的返回值。然后把FutureTask对象(Runnable子类)传给Thread对 象

package ThreadClass;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * @Name:
 * @Author:ZYJ
 * @Date:2019-05-21-20:06
 * @Description:
 */
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;

/**
 * @Name:
 * @Author:ZYJ
 * @Date:2019-05-28-22:57
 * @Description:
 */
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;

/**
 * @Name:
 * @Author:ZYJ
 * @Date:2019-05-28-23:08
 * @Description:
 */
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;

/**
 * @Name:join()练习
 * @Author:ZYJ
 * @Date:2019-05-28-23:32
 * @Description:
 */
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;

/**
 * @Name:线程停止
 * @Author:ZYJ
 * @Date:2019-05-29-10:22
 * @Description:
 */
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;

/**
 * @Name:interrupt()方法练习
 * @Author:ZYJ
 * @Date:2019-05-29-10:55
 * @Description:
 */
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,如果是waitsleepjoin三个方法引起的阻塞,那么会将线程的中断标志置为false,并抛出一个InterrputedEcxception;

​ b,如果在中断时,线程正处于非阻塞状态,则将中断标志修改为true,一旦进入阻塞状态,按照阻塞状态情况来处理。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值