这篇文章主要介绍“java多线程的原理及用法”,在日常操作中,相信很多人在java多线程的原理及用法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”java多线程的原理及用法”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
一、线程的生命周期
JDK中用Thread.State类定义了线程的几种状态:
二、线程同步
1、为什么要有线程同步
2、synchronized
2.1同步代码块
2.2同步方法
3、Lock锁
要想实现多线程,必须在主线程中创建新的线程对象。Java语言使用 Thread类及其子类的对象来表示线程,在它的一个完整的生命周期中通常 要经历如下的五种状态:
新建:当一个Thread类或其子类的对象被声明并创建时,新生的线程 对象处于新建状态;
就绪:处于新建状态的线程被start()后,将进入线程队列等待CPU时间 片,此时它已具备了运行的条件,只是没分配到CPU资源;
运行:当就绪的线程被调度并获得CPU资源时,便进入运行状态, run()方法定义了线程的操作和功能;
阻塞:在某种特殊情况下,被人为挂起或执行输入输出操作时,让出 CPU 并临时中止自己的执行,进入阻塞状态;
死亡:线程完成了它的全部工作或线程被提前强制性地中止或出现异常 导致结束。 在上面五个阶段中,只有新建和死亡是不可重复,其它几个状态都可能改变。
注意:
1.新建和死亡状态只能有一次;
2.运行状态只能是从就绪状态变过来的;
3.阻塞状态不能直接变为运行状态,需要通过就绪状态;
4.当一个运行状态的线程调用yield()方法后,就会变为就绪状态;
5.当一个运行状态的线程调用sleep()、等待同步锁方法、wait()方法或 join()方法时,就会处理阻塞状态;
6.当一个阻塞状态的线程调用notify()/notifyAll()方法,或者sleep()方法 结束,再或者获得同步锁,或者join()线程执行完毕就可以变为就绪状 态的线程
7.当一个线程执行过多后就处理死亡状态,即线程生命周期结束。
为了解决线程安全问题,在多线程下,多个线程对一个数据进行修改时,可能会产生数据出错的问题,所以我们就需要通过线程同步的方法来解决问题。
Java中的线程同步实现方式:
示例:
public class MyRunnableTest { public static void main(String[] args) { MyRunnable myRunnable = new MyRunnable(); Thread thread = new Thread(myRunnable,"A"); Thread thread1 = new Thread(myRunnable,"B"); Thread thread2 = new Thread(myRunnable,"C"); Thread thread3 = new Thread(myRunnable,"D"); Thread thread4 = new Thread(myRunnable,"E"); thread.start(); thread1.start(); thread2.start(); thread3.start(); thread4.start(); } public class MyRunnable implements Runnable{ @Override public void run() { synchronized (Thread.class){ System.out.println(Thread.currentThread().getName()+"在过山洞"); try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } } }
注意: 同步锁可以是任意对象,但该对象必须唯一; 同步代码块所在位置也很重要,同步代码块需要把引起数据问题的所有代码都包裹起,不能多裹,也不能少裹。 我们通常都是使用字节码文件来作为同步锁。
示例:
public class MyRunnableTest { public static void main(String[] args) { MyRunnable myRunnable = new MyRunnable(); Thread thread = new Thread(myRunnable,"A"); Thread thread1 = new Thread(myRunnable,"B"); Thread thread2 = new Thread(myRunnable,"C"); Thread thread3 = new Thread(myRunnable,"D"); Thread thread4 = new Thread(myRunnable,"E"); thread.start(); thread1.start(); thread2.start(); thread3.start(); thread4.start(); } public class MyRunnable implements Runnable{ @Override public void run() { test() } public synchronized void test(){ System.out.println(Thread.currentThread().getName()+"在过山洞"); try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } } }
**注意:**当使用同步方法来处理多线程的共享数据问题,如果是静态方法,使用的是类名.class方式,如果是非静态方法,使用的是this。
使用Lock.lock()进行加锁操作,然后使用Lock.unlock()方法来进行 解锁。
Lock是一个接口,不能直接实例化,需要使用子类来实例化,通常使用的 子类是ReentrantLock。
public class MyRunnableTest { public static void main(String[] args) { MyRunnable myRunnable = new MyRunnable(); Thread thread = new Thread(myRunnable,"A"); Thread thread1 = new Thread(myRunnable,"B"); Thread thread2 = new Thread(myRunnable,"C"); Thread thread3 = new Thread(myRunnable,"D"); Thread thread4 = new Thread(myRunnable,"E"); thread.start(); thread1.start(); thread2.start(); thread3.start(); thread4.start(); } } public class MyRunnable implements Runnable{ Lock lock = new ReentrantLock(); lock.lock(); System.out.println(Thread.currentThread().getName()+"在过山洞"); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); }finally { lock.unlock(); } } }
说明:
在需要作同步操作的代码块之前需要使用Lock.lock()方法来作加锁处 理;在同步操作的代码块之后,增加finally语句块来释放锁,释放锁的方法为Lock.unlock()方法;一定要确保锁能释放,否则就是死锁;
Lock比synchronized更轻量级,功能更强大,如果可以尽量使用Lock。
到此,关于“java多线程的原理及用法”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。