黑马程序员——多线程

本文详细介绍了Java中多线程的基础知识,包括线程的概念、创建方式、线程状态及多线程的好处与弊端。此外,还深入探讨了线程同步、死锁问题、线程通信及线程池等内容。

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

线程
概念:线程是指进程中的执行流程,一个进程中可以运行多个线程。
线程总体分为:守护线程、用户线程。
线程的状态:生、死、可运行、运行、等待/阻塞。

多线程好处、弊端
好处:提高程序的效率,可以同时完成多项工作。
弊端:多线程共执行的代码块容易出现安全隐患。

1.创建线程方式

  • 1.继承Thread类。
  • 好处:直接继承Thread类中的方法,代码简单易懂。
  • 弊端:如果此类有了父类,就使用不了这种方法,类不能多继承。
  • 1.1定义类继承Thread。
  • 1.2重写run方法。
  • 1.3把新线程要做的事写在run方法中。
  • 1.4创建线程对象。
  • 1.5开启新线程,内部会自动执行run方法。

package ThreadDemo;
class MyThread extends Thread
{
    public void run()
    {
        while(true)
        {
            System.out.println("你好!");
        }
    }
}
public class MyThreadDemo
{
    public static void main(String[] args)
    {
        MyThread t = new MyThread();
        t.start();
    }
}
  • 2.实现Runnable接口
  • 好处:定义的线程类有了父类,此法方法一样可以实现。
  • 弊端:需要先获取线程对象,才能得到Thread的方法,过程比较复杂。
  • 2.1定义类实现Runnable接口。
  • 2.2实现run方法。
  • 2.3把新线程要做的事写在run方法中。
  • 2.4创建自定义的Runnable的子类对象。
  • 2.5创建Thread对象,传入Runnable。
  • 2.6调用start()开启新线程,内部会自动调用Runnable的run()方法。

package ThreadDemo;
class MyThread implements Runnable
{
    public void run()
    {
        while(true)
        {
            System.out.println("hello");
        }
    }
}
public class MyThreadDemo
{
    public static void main(String[] args)
    {
        MyThread t = new MyThread();
        new Thread(t).start();
    }
}

2Threa类常用方法

  • 1.获取名字:通过getName()方法获取线程对象的名字。
  • 2.设置线程名字:通过构造函数传入String类型的名字例如:new Thread("线程名字")。
  • 3.获取当前线程对象:Thread.currentThread()(此方法主线程也可以获取)。
  • 4.休眠:通过Thread.sleep(毫秒、纳秒),控制当前线程休眠若干毫秒。
  • 5.守护:通过setDaemon设置一个线程为守护线程。当其他非守护线程都执行结束后,自动退出。
  • 6.加入:join(),当前线程暂停,等待指定的线程执行结束后, 当前线程再继续。join(int), 可以等待指定的毫秒之后继续。

3线程同步
当有线程操作都操作多段代码块时,容易出现安全问题,所以希望执行这段代码的时候只有一个线程,当这个线程执行完后,其他线程才能来执行这个多段代码块,这时就需要同步这代码块。
1synchronized同步

1.1同步代码块

使用synchronized关键字加上一个锁对象来定义一段代码。

package ThreadDemo;
class Resouce
{
    int count = 100;
    public void out()
    {
        synchronized(this)
        {
            System.out.println(count);
            count--;
        }
    }
}
class MyThread implements Runnable
{
    private Resouce res;
    public MyThread(Resouce res)
    {
        this.res = res;
    }
    public void run()
    {
        while(true)
        {
            res.out();
        }
    }
}
public class MyThreadDemo
{
    public static void main(String[] args)
    {
        Resouce res = new Resouce();
        MyThread t1 = new MyThread(res);
        MyThread t2 = new MyThread(res);
        new Thread(t1).start();
        new Thread(t2).start();
    }
}
1.2同步方法
使用synchronized关键字修饰一个方法, 该方法中所有的代码都是同步的。
package ThreadDemo;
class Resouce
{
    int count = 100;
    public synchronized void out()
    {
        System.out.println(count);
        count--;
    }
}
class MyThread implements Runnable
{
    private Resouce res;
    public MyThread(Resouce res)
    {
        this.res = res;
    }
    public void run()
    {
        while(true)
        {
            res.out();
        }
    }
}
public class MyThreadDemo
{
    public static void main(String[] args)
    {
        Resouce res = new Resouce();
        MyThread t1 = new MyThread(res);
        MyThread t2 = new MyThread(res);
        new Thread(t1).start();
        new Thread(t2).start();
    }
}
2使用ReentrantLock类同步(JDK5后)

package ThreadDemo;
import java.util.concurrent.*;
class Resouce
{
    private String sThreadName;
    private int nCount = 1;
    private Boolean bFlag = false;
    private Lock lock= new ReentrantLock();
    private Condition pro = lock.newCondition();
    private Condition con = lock.newCondition();
    void set(String name) throws InterruptedException
    {
        lock.lock();
        try
        {
            while(bFlag)
            {
                pro.await();
            }    
            this.sThreadName = name+"--"+nCount++;
            System.out.println(Thread.currentThread()+"生产"+"---"+this.sThreadName);
            bFlag = true;
            con.signal();
        }
        finally
        {
            lock.unlock();
        }
    }
    void out() throws InterruptedException
    {
        lock.lock();
        try
        {
            while(!bFlag)
            {
                con.await();
            }
            System.out.println(Thread.currentThread()+"***消费"+"---"+this.sThreadName);
            bFlag = false;
            pro.signal();
        }
        finally
        {
            lock.unlock();
        }
    }
}
class Consumer implements Runnable
{
    private Resouce res;
    Consumer(Resouce res)
    {
        this.res = res;
    }
    public void run()
    {
        while(true)
        {
            try
            {
                res.out();
            }
            catch (Exception e)
            {
                System.out.println("消费商品失败!");
            }
        }
    }
}
class Produce implements Runnable
{
    private Resouce res;
    public Produce(Resouce res)
    {
        this.res = res;
    }
    public void run()
    {
        while(true)
        {
            try
            {
                res.set("商品");
            }
            catch (Exception e)
            {
                System.out.println("生产商品失败!");
            }
        }
    }
}
public class ThreadDemo2
{

    public static void main(String[] args)
    {
        Resouce res = new Resouce();
        Produce p = new Produce(res);
        Consumer c = new Consumer(res);
        Thread t1 = new Thread(p);
        Thread t2 = new Thread(p);
        Thread t3 = new Thread(c);
        Thread t4 = new Thread(c);
        Thread t5 = new Thread(c);
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
    }
}
4死锁问题
使用同步嵌套,使用了相同锁,就可能出现死锁
package ThreadDemo;
class MyThread implements Runnable
{
    private Boolean flag;
    public MyThread()
    {}
    public MyThread(Boolean flag)
    {
        this.flag = flag;
    }
    public void run()
    {
        while(true)
        {
            if(flag)
            {
                synchronized (MyThreadDemo.A)
                {
                    System.out.println("if-A锁");
                    synchronized (MyThreadDemo.B)
                    {
                        System.out.println("if-B锁");
                    }
                }
            }
            else
            {
                synchronized (MyThreadDemo.B)
                {
                    System.out.println("else-B锁");
                    synchronized (MyThreadDemo.A)
                    {
                        System.out.println("else-A锁");
                    }
                }
            }
        }
    }
}
public class MyThreadDemo
{
    static String A = "a";
    static String B = "b";
    public static void main(String[] args)
    {
        MyThread t1 = new MyThread(true);
        MyThread t2 = new MyThread(false);
        new Thread(t1).start();
        new Thread(t2).start();
    }
}
5多线程通信
多线程并发执行时,我们控制线程的有规律的执行(默认是CPU随机切换执行),就可以使用通信。

5.1JDk5以前
  • 1.wait():线程等待。
  • 2.notify():随机唤醒一个线程。
  • 3.notifyAll():唤醒所有线程。
5.2JDk5以后
  • 1.使用ReentrantLock类的newCondition()方法可以获取Condition对象。
  • 2.需要等待线程的时候使用Condition的await()方法, 需要被唤醒的线程时候用Conditon的signal()方法。
  • 3.不同的线程使用不同的Condition, 这样就能区分唤醒的时候找哪个线程了。

6.线程池(JDK5后)
线程池的基本思想还是一种对象池的思想,开辟一块内存空间,里面存放了众多(未死亡)的线程,池中线程执行调度由池管理器来处理。
线程池的常见类型:固定尺寸的线程池、可变尺寸的连接池。

固定尺寸线程池

package ThreadDemo;
import java.util.concurrent.*;
class MyThread implements Runnable
{
    public void run()
    {
        System.out.println(Thread.currentThread().getName()+"执行了!");
    }
}
public class ExService
{
    public static void main(String[] args)
    {
        MyThread t = new MyThread();
        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        Thread t3 = new Thread(t);
        Thread t4 = new Thread(t);
        Thread t5 = new Thread(t);
        ExecutorService pool = Executors.newFixedThreadPool(2); //创建固定大小的线程池。
        pool.execute(t1); //把线程加入到线程池中。
        pool.execute(t2);
        pool.execute(t3);
        pool.execute(t4);
        pool.execute(t5);
        pool.shutdown();
    }
}
单任务线程池
只需要把pool的创建方式ExecutorService pool = Executors.newFixedThreadPool(2);改成
ExecutorService pool = Executors.newSingleThreadExecutor(); //创建固单个线程执行的线程池。
可变尺寸的线程池
只需要把pool的创建方式ExecutorService pool = Executors.newCachedThreadPool();
延迟连接池
线程在给定的延迟后运行命令,或者定期的执行
package ThreadDemo;
import java.util.concurrent.*;
class MyThread implements Runnable
{
    public void run()
    {
        System.out.println(Thread.currentThread().getName()+"执行了!");
    }
}
public class ExService
{
    public static void main(String[] args)
    {
        MyThread t = new MyThread();
        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        Thread t3 = new Thread(t);
        Thread t4 = new Thread(t);
        Thread t5 = new Thread(t);
        ScheduledExecutorService pool = Executors.newScheduledThreadPool(2); //创建延迟线程执行的线程池。
        pool.execute(t1); //把线程加入到线程池中。
        pool.schedule(t3, 1, TimeUnit.MINUTES); //线程延迟1分钟执行。
        pool.execute(t2);
        pool.execute(t4);
        pool.execute(t5);
        pool.shutdown();
    }
}
自定义线程池
package ThreadDemo;
import java.util.concurrent.*;
class MyThread implements Runnable
{
    public void run()
    {
        System.out.println(Thread.currentThread().getName()+"执行了!");
    }
}
public class ExService
{
    public static void main(String[] args)
    {
        MyThread t = new MyThread();
        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        Thread t3 = new Thread(t);
        Thread t4 = new Thread(t);
        Thread t5 = new Thread(t);
        BlockingQueue<Runnable> bque = new ArrayBlockingQueue<Runnable>(20);
        ThreadPoolExecutor poo = new ThreadPoolExecutor(2, 3,2, TimeUnit.MICROSECONDS, bque);
        ScheduledExecutorService pool = Executors.newScheduledThreadPool(2); //创建固单个线程执行的线程池。
        pool.execute(t1); //把线程加入到线程池中。
        pool.execute(t2);
        pool.execute(t3);
        pool.execute(t4);
        pool.execute(t5);
        pool.shutdown();
    }
}
创建自定义线程池的构造方法很多,ThreadPoolExecutor就是其中一个,这个方法的蚕食含义如下:
public ThreadPoolExecutor(int corePoolSize,
            int maximumPoolSize,
            long keepAliveTime,
             TimeUnit unit,
            BlockingQueue<Runnable> workQueue)
参数:
  • corePoolSize -池中所保存的线程数,包括空闲线程。
  • maximumPoolSize -池中允许的最大线程数。
  • keepAliveTime -当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。
  • unit - keepAliveTime参数的时间单位。
  • workQueue -执行前用于保持任务的队列。此队列仅保持由execute方法提交的Runnable任务。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值