java的线程与线程的基本应用

**什么是线程:**在一个程序中,能够独立运行的程序片段叫做“线程”,利用它进行编写的程序叫做多线程处理程序。通常情况下,多线程程序能够更好低利用计算机资源,提高程序执行的效率。多线程编程具有重要的意义,每个程序员都应该掌握。
**举例说明:**一做雪糕的工厂(雪糕厂相当于cpu,负责资源的调配),能做出小布丁和绿色心情。但是,由于工厂电力系统原因,只能开一条生产线。(两条生产线相当于两个进程)现在我们开始做小布丁,小布丁生产线上的员工,就相当于一个线程。一个进程里面至少包涵一个线程。而一个进程,可以为我们提供服务。我们常用的main方法,就是一个线程,而且是主线程。
可以打开电脑的任务管理器,上面有很多进程,每个进程都是有一个或者多个线程组成的。

线程的声明周期

1、新建状态:用Thread的new语句创建了线程对象,此时对象只在对内存中分配了内存。
2、就绪状态:当新建状态下的线程对象调用了start()方法后,该线程就进入了就绪状态,处于这个状态的线程位于可运行池中,等待获得CPU使用权。
3、运行状态:正在被CPU执行的线程状态。
4、阻塞状态:当线程因为某种原因处于阻塞状态时,JVM不会给线程分配CPU,直到线程重新进入就绪状态,才有机会被CPU运行。
  阻塞分为三种状态:
  1) 位于对象等待池中的阻塞状态:当线程运行获取对象锁后,执行了Object.wait()方法,JVM就会把该线程加入对象的等待池中,这种状态必须等待其他线程调用同个对象的notify()或notifyAll()方法时才有可能激活为就绪状态;
  2) 位于对象锁中的阻塞状态:当线程运行时,试图获取某个对象的同步锁时,如果该对象的同步锁已被其他线程占用,则JVM就会把当前线程放入对象的锁池中,当对象的同步锁被释放后,JVM就会根据一定的调度算法,将处于对象锁中阻塞状态的某个线程激活为就绪状态;
  3) 其他阻塞状态:当线程执行了sleep()方法,或者调用了其他线程的join()方法,或发出了I/O请求时,线程就会进入这个状态。

Java创建多线程的几种方式

1、通过继承Thread类创建线程(了解即可,不常用)
  通过这种方式创建的线程之间是彼此相互独立的,各自有用自己的资源,互不干扰。
  假设一个影院有三个售票口,分别用于向儿童、成人和老人售票。影院为每个窗口放有100张电影票,分别是儿童票、成人票和老人票。三个窗口需要同时卖票,而现在只有一个售票员,这个售票员就相当于一个CPU,三个窗口就相当于三个线程。代码如下:

public class ThreadCreate {

    public static void main(String[] args) {
        MyThread m1 = new MyThread("窗口1");
        MyThread m2 = new MyThread("窗口2");
        MyThread m3 = new MyThread("窗口3");
        m1.start();
        m2.start();
        m3.start();
    }
}
class MyThread extends Thread {
    private int ticket = 1;
    MyThread(String name) {
        super(name);
    }
    public void run(){
        while (ticket <= 100) {
            String threadName = Thread.currentThread().getName();
            System.out.println("【" + threadName + "】售出第【" + ticket++ + "】张票");
        }
    }
}

2、通过实现Runnable接口创建线程(推荐使用)
  通过继承Thread类创建的多线程可以满足非协同工作的多线程需求,但当要求各个线程之间需要处理共享资源时,只能通过实现Runnable接口的方式。
 假设上述影院的三个售票窗口销售的是同一种票,一共100一张票,每个窗口都可以卖票。代码如下:

package com.boot.test.test;

public class RunnableCreate {
    public static void main(String[] args) {
        MyRunnable m =new MyRunnable();
        Thread  m1 = new Thread(m,"窗口1");
        Thread  m2 = new Thread(m,"窗口2");
        Thread  m3 = new Thread(m,"窗口3");
        m1.start();
        m2.start();
        m3.start();
    }
}
class MyRunnable   implements Runnable {
    private int ticket = 1;
    public void run(){
        while (ticket <= 100) {
            String threadName = Thread.currentThread().getName();
            System.out.println("【" + threadName + "】售出第【" + ticket++ + "】张票");
        }
    }
}

3、通过FutureTask类创建带返回值的线程(需要获得线程返回值时使用)
FutureTask是一种可以取消的异步的计算任务。它的计算是通过Callable实现的,它等价于可以携带返回值的Runnable。
 FutureTask是为了弥补Thread的不足而设计的,它可以让程序员准确地知道线程什么时候执行完成并获得到线程执行完成后返回的结果(如果有需要)。
 假设某个计算有两个步骤,综合计算结果为两个步骤结果的总和,可以将耗时较长的计算步骤通过FutureTask创建的线程来执行,等它计算结束,然后计算综合结果。代码如下:

class MyCallable implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        Integer result = (new Random()).nextInt(10);
        System.out.println("请等待2000");
        Thread.sleep(2000);
        return result;
    }
}
public class FutureTaskCreate {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        //计算方法1的结果
        FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyCallable());
        new Thread(futureTask).start();
        Integer result1 = (new Random()).nextInt(10);
        System.out.println("步骤1结果已经计算完毕,结果为:"+result1.intValue());
        while (!futureTask.isDone()) {
            try {
                Thread.sleep(500);
                System.out.println("步骤2的结果还在计算中,请稍等....");
            }catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        Integer result2 = futureTask.get();
        System.out.println("步骤2结果已经计算完毕,结果为:"+result2.intValue());
        System.out.println("综合计算结果为:" + (result1.intValue() + result2.intValue()));
    }
}

synchronized 与线程之间的关系

java的关键字,用它来修饰一个方法或一个代码块的时候,能够保证在同一个时刻最多只有一个线程执行该段代码,可保证修饰的代码在执行过程中不会被其他线程干扰,即原子性。
一、synchronized可修饰的对象
1.synchronized {普通方法}:同一时间只能有一个线程访问同一个对象的该方法。缺点:同步整个方法效率不高。
2. synchronized {代码块}:对代码块执行线程同步,效率要高于对整个函数执行同步,推荐使用这种方法。
3. synchronized {static方法}:加锁的对象是类,同一时间,该类的所有对象中的synchronized static方法只能有一个线程访问。
注:使用synchronized应重点理解以下细节
1.当多个并发线程访问同一个对象的同步代码块时,一段时间内只能有一个线程得到执行,其他线程必须等待当前线程执行完代码块后再执行代码;
2. 当一个线程访问一个对象的同步代码块时,其他线程可以访问该对象的中的非同步代码块;
3. 当一个线程访问一个对象的同步代码块时,其他线程对该对象中的所有同步代码块均不能访问;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值