A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始


如果对什么是线程,什么是进程仍存有疑惑,请先Google之,因为这两个概念不在文本的范围之内。
用多线程只有一个目的,那就是更好的利用CPU的资源,因为所有的多线程代码都可以用单线程来实现。说这个话其实只有一半对,因为反应“多角色”的程序代码,最起码每个角色要给他一个线程吧,否则连实际场景都无法模拟,当然也没法说能用单线程来实现:比如最常见的“生产者,消费者模型”。
很多人都对其中的一些概念不够明确,如同步,并发等等,让我们先建立一个数据字典,以免产生误会。
   1.多线程:指的是这个程序(一个进程)运行时产生了不止一个线程
   2.并行与并发:
       (1)并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。
       (2)并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。并发往往在场景中有公用的资源,那么针           对这个公用的资源往往产生瓶颈,我们会用TPS或者QPS来反应这个系统的处理能力。
       (3)并发与并行:
           线程安全:经常用来描绘一段代码。指在并发的情况下,该代码经过多线程使用,线程的调度顺序不影响任何结果。这个时候使用              多线程,我们只需要关注系统的内存,cpu是不是够用即可。反过来,线程不安全就意味线程的调度顺序会影响结果。
           同步:java中的同步指的是通过人为的控制和调度,保证共享资源的多线程访问成为线程安全,来保证结果的准确。如上面的代码              简单加入synchronized关键字。在保证结果准确的同时,提高性能,才是优秀的程序。线程安全的优先级高于性能。
扎好马步:线程的状态
线程状态:
每个对象都有的方法(机制)
synchronized单独使用:
   使用同步代码块格式:
    synchronized(锁对象){
        可能会出现线程安全问题的代码(访问了共享数据的代码)
    }
注意:
    1.通过代码块中的锁对象,可以使用任意的对象
    2.但是必须保证多个线程使用的锁对象是同一个
    3.锁对象作用:
        把同步代码块锁住,只让一个线程在同步代码块中执行 使用synchronized的同步代码块,和静态代码块(静态调用静态)附上两张图片看一下:同步代码块 静态代码块 前面的synchronized两种形式还有最后一种方案,就是用lock锁来解决解决线程安全问题的三种方案:使用Lock锁java.util.concurrent.locks.Lock接口
Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。
Lock接口中的方法:
    void lock()获取锁。
    void unlock()  释放锁。
java.util.concurrent.locks.ReentrantLock implements Lock接口

使用步骤:
    1.在成员位置创建一个ReentrantLock对象
    2.在可能会出现安全问题的代码前调用Lock接口中的方法lock获取锁
    3.在可能会出现安全问题的代码后调用Lock接口中的方法unlock释放锁附上一张图片:
创建多线程程序的第二种方式:实现Runnable接口 (第一种方法可以用继承类来实现,但是继承类是单继承的,所以不提倡)java.lang.Runnable Runnable接口应该由那些打算通过某一线程执行其实例的类来实现。类必须定义一个称为run的无参数方法。java.lang.Thread类的构造方法Thread(Runnable target)分配新的Thread对象Thread(Runnable target,String name)分配新的Thread对象。实现步骤:
    1.创建一个Runnable接口的实现类
    2.在实现类中重写Runnable接口的run方法,设置线程任务
    3.创建一个Runnable接口的实现类对象
    4.创建Thread类对象,构造方法中传递Runnable接口的实现类对象
    5.调用Thread类中的start方法,开启新的线程执行run方法

实现Runnable接口创建多线程程序的好处:
    1.避免了单继承的局限性
        一个类只能继承一个类(一个人只能有一个亲爹),类继承了Thread类就不能继承其他的类
        实现了Runnable接口,还可以继承其他的类,实现其他的接口
    2.增强了程序的扩展性,降低了程序的耦合性(解耦)
        实现Runnable接口的方式,把设置线程任务和开启新线程进行了分离(解耦)
        实现类中,重写了run方法:用来设置线程任务
        创建Thread类对象,调用start方法:用来开启新线程这里就写一个60秒的小程序来表示一下: 除了实现多线程的两种方式,与解决线程安全问题的三种方式还有一些小的方法,如:setName赋值名字方法,getName得到名字方法如:RunnableImpl r = new  RunnableImpl(); //创立三个线程Thread t = new Thread(r);Thread t1 = new Thread(r);Thread t2 = new Thread(r);t.setName("线程1").start;t1.setName("线程2").start;t2.setName("线程3").start;或者直接:Thread t = new Thread(r,"线程1");Thread t1 = new Thread(r,"线程2");Thread t2 = new Thread(r,"线程3");在这里,在加深一下:直接用匿名方法来做new Thread(r,"线程1").start;  比较简单一下

扩展:
死锁的实现:死锁:资源有限!多个线程中同步代码块形成了嵌套关系。都在抢夺另外一个资源!public class Test03 {    public static void main(String[] args) {       String left = "筷子左";       String right = "筷子右";       new Thread() {           @Override           public void run() {               while(true) {                    synchronized (left) {                        System.out.println("我抢到了筷子左,正在等待筷子右");                        synchronized (right) {                            System.out.println("我抢到了筷子右,开吃!");                        }                    }               }           }       }.start();       new Thread() {           @Override           public void run() {               while(true) {                   synchronized (right) {                       System.out.println("班长抢到了筷子右,正在等待筷子左");                       synchronized (left) {                           System.out.println("班长抢到了筷子左,开吃!");                       }                   }               }           }       }.start();    }}死锁,了解就好!


















0 个回复

您需要登录后才可以回帖 登录 | 加入黑马