Java多线程知识

Java多线程

学习Java多线程前要了解的内容

1.   什么是线程?

要说到什么事线程,必须先说到什么是进程,书上是这么说的:“进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础”,回到什么是线程的问题上:“线程是程序执行流的最小单元”,其实进程就相当于一个空间,进程运行时,实际运行的是进程中的线程。

打一个可能不太恰当的例子:就好比进程是一个,你的手打篮球投球,吃饭啊,你的脚踢足球,你的身体的各个部件都在做不同的工作,而你打篮球的时候也要用腿跑,也就是在进程中的线程可以相互协作,做一件事,而且你打篮球的时候,手给脚穿鞋,也就是线程间也可以相互通信;每一个进程至少有一个线程,那就是主线程,就像人只要活着肯定至少在做着一件事情,哪怕是睡觉也好。

2.   多线程有什么作用?

多线程可以提高程序的效率,让程序更有可能获得更多的CPU时间;就好像做一件很复杂的事情,一个人做肯定要很久,但是有很多个人人帮着做,做起来肯定就快了。

3.   线程的状态有哪些?

一般说有3种

就绪:线程分配了CPU以外的全部资源,等待获得CPU调度

执行:线程获得CPU,正在执行

阻塞:线程由于发生I/O或者其他的操作导致无法继续执行,就放弃处理机,转入线程就绪队列

 

 

好,说了这么多,下面我们来看一下Java的多线程该怎么写:

4.   Java中线程的实现方式

1)        java已经提供了对线程这类事物的描述。就是Thread类。创建线程的第一种方式:继承Thread类。

步骤:

1定义类继承Thread。

2复写Thread类中的run方法

 目的:将自定义代码存储在run方法。让线程运行。

3调用线程的start方法,该方法两个作用:启动线程,调用run方法。

来,上代码:

package learn.threads;
 
class ThreadTest extends Thread
{
       @Override
       public void run()
 
       {
              System.out.println("我是新线程!");
       }
}
 
public class ThreadDemo
 
{
 
       public static void main(String[] args)
 
       {
 
              ThreadTest t = new ThreadTest();// 创建好一个线程。
 
              t.start();// 开启线程并执行该线程的run方法。
 
              // t.run(); 仅仅是对象调用方法。而线程创建了,并没有运行。
 
              for (int x = 0; x < 10; x++)
 
                     System.out.println("主线程--" + x);
 
       }
 
}


 

运行结果:(由于是多线程,每台计算机上的运行结果肯能不同哦

 

主线程--0
主线程--1
主线程--2
主线程--3
主线程--4
我是新线程!
主线程--5
主线程--6
主线程--7
主线程--8
主线程—9


 

可以看到在多线程条件下,主线程和新线程可以并行执行

 

2)        第二种方式:实现Runable接口(建议)。

步骤:

a)定义类实现Runnable接口。

b)覆盖Runnable接口中的run方法,将线程要运行的代码存放在该run方法中。

c)通过Thread类建立线程对象

d)将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。

为什么要将Runnable接口的子类对象传递给Thread的构造函数?

因为自定义的run方法所属的对象是Runnable接口的子类对象。所以要让线程去指定指定对象的run方法。就必须明确该run方法所属对象。

5调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。

例子:

package learn.threads;
 
class Resource implements Runnable
{
       @Override
       public void run()
       {
              System.out.println("我是新线程!");
 
       }
}
class ThreadDemo
 
{
       public static void main(String[] args)
       {
              Resource r = new Resource();// 创建资源对象
              Thread t = new Thread(r);// 创建了一个线程;
              t.start();// 运行线程t
       }
}


5.   Java中线程的两种实现方式的区别

两种实现方式区别:

继承Thread线程代码存放Thread子类run方法中。

实现Runnable线程代码存在接口的子类的run方法,避免了单继承的局限性。

由于Java的单继承多实现,所以在定义线程时,建议使用实现Runnable方式

6.   Java中线程相关的方法

1)        static Thread Thread.currentThread():获取当前线程对象。

2)        线程对象.getName(): 获取线程名称。

3)        设置线程名称:setName或者构造函数,或者运用Thread构造函数Thread(Runnable target, String name)线程都有自己默认的名称。Thread-编号 该编号从0开始。

7.   Java中多线程的安全问题

其实Java对于多线程的安全问题提供了专业的解决方式: 例如对象锁(Lock);持有锁的线程可以在同步中执行;没有持有锁的线程即使获取CPU的执行权,也进不去,因为没有获取锁;用人话说就好比:很多个人同时都要上厕所,但是厕所只有一间,同时只能由一个人用,而其他人只能够等待。

1)        同步的前提:

a)        必须要有两个或者两个以上的线程。

b)        必须是多个线程使用同一个锁。

c)        必须保证同步中只能有一个线程在运行。

2)        同步的优缺点:

优点:解决了多线程的安全问题。

缺点:多个线程需要判断锁,较为消耗资源。

3)        线程同步的方式:

a)        使用同步代码块。

 

synchronized (对象)
{
//需要同步的操作
}
b)        使用同步函数。
        public synchronized void show()
{
//需要同步的操作
}

b)        使用同步函数。

       

 public synchronized void show()
{
//需要同步的操作
}



4)        同步函数用的锁

函数需要被对象调用,那么函数都有一个所属对象引用,就是this,所以同步函数使用的锁是this,即对象本身。

5)        静态同步函数

public static synchronized void show()
       {
              // 需同步的代码。
       }


静态同步函数使用的锁是该同步函数所属类的class对象,也就是类名.class,因为静态方法中也不可以定义this,而且静态类在内存中没有本类对象的,但是一定有该类对应的字节码文件对象。所以静态同步函数使用的锁是该方法所在类的字节码文件对象。

 

6)        线程死锁问题

举个例子:两个人(两个线程)一起吃饭,但是只有一双筷子(对象锁),而且每个人都只拿到了一双筷子中的一支,如果两个人都不妥协的话,两个人都吃不上饭。这个例子体现到代码中就是

 

package learn.threads;
 
class EatRice implements Runnable {
       Object chopstick;
 
       /*传入哪个人有那根筷子*/
       EatRice(Object chopstick) {
              this.chopstick = chopstick;
       }
 
       /*模拟两个人吃饭*/
       public void run() {
              if (chopstick == Chopsticks.chopstick1) {
                     while (true) {
                            synchronized (Chopsticks.chopstick1) {
                                   /* 请求筷子 */
                                   System.out.println(Thread.currentThread().getName()
                                                 +"要第二根筷子");
                                   synchronized (Chopsticks.chopstick2) {
                                          /* 吃饭 */
                                          eat(Thread.currentThread().getName());
                                   }
                            }
                     }
              } else
                     while (true)
                            synchronized (Chopsticks.chopstick2) {
                                   /* 请求筷子 */
                                   System.out.println(Thread.currentThread().getName()
                                                 +"要第一根筷子");
                                   synchronized (Chopsticks.chopstick1) {
                                          /* 吃饭 */
                                          eat(Thread.currentThread().getName());
                                   }
                            }
       }
 
       /*吃饭方法*/
       public synchronized void eat(String name) {
              System.out.println(name + "正在吃饭");
       }
}
 
/* 一双筷子*/
class Chopsticks {
       /* 第一根筷子 */
       static Object chopstick1 = new Object();
       /* 第二根筷子 */
       static Object chopstick2 = new Object();
}
 
/* 死锁测试*/
public class DeadLockDemo {
       public static void main(String[] args) {
              /* newEatRice(Chopsticks.chopstick1)表示第一个人一开始拿到了第一根筷子 */
              Thread person1 = new Thread(new EatRice(Chopsticks.chopstick1), "第一个人");// 第一个人
              /* newEatRice(Chopsticks.chopstick1)表示第二个人一开始拿到了第二根筷子 */
              Thread person2 = new Thread(new EatRice(Chopsticks.chopstick2), "第二个人");// 第二个人
              person1.start();
              person2.start();
       }
}


运行结果如下(可想而知,就是这两个人都没吃上饭):

 

第二个人要第一根筷子
第一个人要第二根筷子


因此我们在多线程编程时不要同步中嵌套同步。

 

7)        等待唤醒机制

方法:

a)锁所在的对象.wait();//所执行中的线程等待,并释放锁,放弃执行资格。

b)锁所在的对象.notify();//唤醒同一锁中等待中的一个线程

c)锁所在的对象.notifyAll();//唤醒同一锁中等待中的全部线程  

d)锁所在的对象.wait(); 方法会抛出InterruptedExc
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值