多线程

Thread有单继承局限性所以不建议使用,但是所有的线程对象一定要通过Thread里中的star
         t()方法 Runnable使用时可以避免单继承的局限,所以建议使用此操作
                 Callable比Runnable唯一的好处是多了返回值的数据


一:进程与线程


概述:几乎任何的操作系统都支持运行多个任务,通常一个任务就是一个程序,而一个程序就是一个进程。当一个进程运行时,
   内部可能包括多个顺序执行流,每个顺序执行流就是一个线程。
   进程:进程是指处于运行过程中的程序,并且具有一定的独立功能。进程是系统进行资源分配和调度的一个单位。当程序进
   入内存运行时,即为进程。
   进程的三个特点:
1:独立性:进程是系统中独立存在的实体,它可以独立拥有资源,每一个进程都有自己独立的地址空间,没有进程本身的运行,
   用户进程不可以直接访问其他进程的地址空间。
2:动态性:进程和程序的区别在于进程是动态的,进程中有时间的概念,进程具有自己的生命周期和各种不同的状态。
3:并发性:多个进程可以在单个处理器上并发执行,互不影响。
   并发性和并行性是不同的概念:并行是指同一时刻,多个命令在多个处理器上同时执行;并发是指在同一时刻,只有一条命
   令是在处理器上执行的,但多个进程命令被快速轮换执行,使得在宏观上具有多个进程同时执行的效果


线程:
线程是进程的组成部分,一个进程可以拥有多个线程,而一个线程必须拥有一个父进程。线程可以拥有自己的堆栈,自己的程序
   计数器和自己的局部变量,但不能拥有系统资源。它与父进程的其他线程共享该进程的所有资源。
线程的特点:
线程可以完成一定任务,可以和其它线程共享父进程的共享变量和部分环境,相互协作来完成任务。
线程是独立运行的,其不知道进程中是否还有其他线程存在。
线程的执行是抢占式的,也就是说,当前执行的线程随时可能被挂起,以便运行另一个线程。
一个线程可以创建或撤销另一个线程,一个进程中的多个线程可以并发执行。
二、线程的创建及使用


java使用Thread类代表线程,所有的线程对象都必须是Thread或者其子类的实例,每个线程的作用是完成一定任务,实际上是就是
   执行一段程序流(一段顺序执行的代码)
方案一:继承Thread类创建线程类
步骤: ① 定义Thread类的子类 并重写该类的Run方法,该run方法的方法体就代表了该线程需要完成的任务
        ② 创建Thread类的实例,即创建了线程对象
        ③ 调用线程的start方法来启动线程


class MyThread extends Thread {
private String name;


public MyThread(String name) {
this.name = name;
}


@Override
public void run() {
for (int x = 0; x < 10; x++) {
System.out.println(this.name + "x=" + x);
}
}
}
public class ThreadTest {
public static void main(String[] args) {
MyThread m1 = new MyThread("线程B");
MyThread m2 = new MyThread("线程B");
MyThread m3 = new MyThread("线程C");
        m1.start();
        m1.start();
        m2.start();
        m3.start();
}
}
方案二:实现Runnable接口
 ①定义Runnable接口的实现类,并重写它的Run方法,run方法同样是该线程的执行体!
 ②创建Runnable实现类的实例,并将此实例作为Thread的target创建一个Thread对象,该Thread对象才是真正的线程对象!
 ③调用start方法启动该线程
class MyThread implements Runnable {
private String name;


public MyThread(String name) {
this.name = name;
}


@Override
public void run() {
for (int x = 0; x < 10; x++) {
System.out.println(this.name + "x=" + x + Thread.currentThread().getName());
}
}
}


public class ThreadTest {
public static void main(String[] args) {
MyThread m1 = new MyThread("线程B");
Thread th = new Thread(m1,"线程1");
th.start();
}
}
结论:采用Ruunable接口的方式创建多个线程可以共享线程类的实例变量,这是因为在这种方式下,程序创建的Runnable对象只是线程的target,
      而多个线程可以共享一个target,所以多个线程可以共享一个实例变量 
      通过Runnable实现多线程其实就是将run包装成线程的执行体,但是目前java无法将任意方法包装成线程执行体


方案三:使用callable和future创建线程
       从Java5开始,Java提供 Callable接口,Callable接口提供了一个call()方法可以作为线程执行体,看起来和Runnable很像,但call()方法更强大
       ——call()方法可以有返回值、call()方法可以抛出异常
       Java5提供了Future接口来代表Callable接口的call()方法的返回值,并为Future接口提供了一个FutureTask实现类,该实现类实现类Future接口,
       也实现了Runnable接口——可以作为Thread的target。


实现步骤:
①创建Callable接口的实现类,并实现call方法,该call方法会成为线程执行体,且call方法具有返回值,在创建callable接口的实现类!
②使用FutrueTask类来包装Callable对象,该FutrueTask封装类Callable的call方法的返回值
③使用FutrueTask对象作为Thread的target创建并启动新线程!
④使用FutrueTask的get方法获取执行结束后的返回值
class MyThread implements Callable<Integer> {
    int  i = 0;
@Override
public Integer call() throws Exception {
for(;i > 20; i++) {
System.out.println(Thread.currentThread().getName());
}
return i;
}
}


public class ThreadTest {
public static void main(String[] args) throws Exception, ExecutionException {
MyThread m1 = new MyThread();
FutureTask<Integer> ft = new FutureTask<>(m1);
Thread th = new Thread(ft,"线程1");
th.start();
System.out.println(ft.get());
}
}
结论:采取Runnable、Callable的优势在于——线程类只是实现了Runnable或Callable接口,还可以继承其它类;在这种方法下,
      多个线程可以共享一个target对象,因此非常适合多个相同线程处理同一份资源的情况,从而将CPU、代码和数据分开,形参清晰的模型,
      体现了面对对象的编程思想。劣势在于编程复杂度略高。




线程的命名和取得


从本质上来讲线程的运行状态并不是固定的。所以来讲要想确定线程的执行,唯一的区别就在于线程的名称上。在起名的时候
就应该尽可能的避免重复,或者避免修改名称
在Thread类中提供可以实现线程名称的操作。
    构造方法:public Thread(Runnable tagget,String name)
    设置名称:public final void setName(String name)
    取得名字:public final void getName(String name)
既然线程的执行本身是不确定的状态,所以如果要取得线程名字的话,那么唯一能做的就是获取当前线程的名字
所以在Thread类中提供了这样的方法:public static Thread currentThread()
如果线程的命名没有指定那么它有默认的名字


class MyThread implements Runnable{


@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName());
}


}


public class ThreadTest {
public static void main(String[] args) throws Exception, ExecutionException {
        Thread th = new Thread(new MyThread(),"我的线程7777");
        th.start();
        th.run();
}
}
返回结果
main
我的线程7777


线程一定是依附于进程存在的,但是现在的进程在哪里哪?
当使用Java命令在jvm上程序执行的时候,那么都会默认的启动一个JVM的进程
,所以整个程序一直都在跑在线程的运行机制上。
每一个jvm至少会执行两个进程,main和gc线程


线程的休眠


class MyThread implements Runnable{


@Override
public void run() {
for(int i = 0;i < 10; i++ ) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("我被中断段了");
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
}
}


public class ThreadTest {
public static void main(String[] args) throws Exception, ExecutionException {
        Thread th = new Thread(new MyThread(),"我的线程7777");
        th.start();
        Thread.sleep(2000);
        th.interrupt();
}
}


输出
我的线程7777
我被中断段了
java.lang.InterruptedException: sleep interrupted
我的线程7777
at java.lang.Thread.sleep(Native Method)
at com.imnu.th.MyThread.run(ThreadTest.java:13)
at java.lang.Thread.run(Unknown Source)
我的线程7777


线程的中断一定是另一个线程将其中断的




线程的优先级
从理论上来讲越高的线程越有可能先执行,而在Thread类里而定义有一下的优先级的操作
  设置优先级 public final void setProirity
  取得优先级 public final void getProirity
1.线程的名字,Thread.currentThread取得当前线程
2.线程的休眠是有先后顺序的
3.理论上线程的优先级越高越有可能先执行。


重点:尽管JDK有十个优先级,但是与大多数的操作系统是不能很好的映射,唯一可以移植方法是调整优先级的时候,
      只有MAX_PRIORITY,NORM_PRIORITY,MIN_PRIORITY
三种机制






加入同步代码的执行速度慢了,而且不像没有同步那时候那样,多个线程会一起进入到方法中
异步的速度要
class MyThread implements Runnable {
private int ticket = 5;


@Override
public void run() {
for (int i = 0; i < 100; i++) {
synchronized (this) {
if (this.ticket > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "ticket" + this.ticket--);
}
}
}
}
}


public class ThreadTest {
public static void main(String[] args) throws Exception, ExecutionException {
MyThread th = new MyThread();
Thread th1 = new Thread(th, "a");
Thread th2 = new Thread(th, "b");
Thread th3 = new Thread(th, "b");
th1.setPriority(Thread.MAX_PRIORITY);
th2.setPriority(Thread.MIN_PRIORITY);
th1.start();
th2.start();
th3.start();
}
}















發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章