JAVA基础-多线程

Posted 阿拉巴洞

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA基础-多线程相关的知识,希望对你有一定的参考价值。


一、线程与进程   

    进程:正在计算机中运行的一个程序,当一个程序进入内存运行,即变成一个进程。一个软件至少有一个进程,
有的软件在点击一个应用图标是可能会给你开多个进程,如:360全家桶。
    线程:软件在计算机中执行的一条路径。软件可以是多线程的。
    总结:一个程序运行后至少有一个进程,一个进程中可以包含多个线程。而多线程就是一个程序中有多个线程
在同时执行。而JAVA为我们提供了2种方式实现多线程:1、继承Thread类 2、实现Runnable接口。我们在编写程
序时的主方法就是一个单独的线程,线程名叫 "main"。而JAVA虚拟机Jvm运行是多线程运行。

二、Thread类

    JAVA实现多线程其中的一种方法就是继承Thread类,Thread是程序中的执行线程。Java 虚拟机允许应用程序并
发地运行多个执行线程。Thread类常用的构造方法有:1、分配新的 Thread 对象 - Thread(),2、分配新的Thread
对象,将指定的name作为线程名称 - Thread(String name)。其常用的方法有:
1、改变线程名称,使之与参数 name 相同:setName(String name)
2、该线程要执行的操作:run()
3、在指定的毫秒数内让当前正在执行的线程休眠(暂停执行):sleep()
4、使该线程开始执行;Java 虚拟机调用该线程的 run 方法:start()
5、返回该线程的名称:getName()
6、静态方法,返回值为Thread对象 - 返回对当前正在执行的线程对象的引用:currentThread()
    A:创建线程的步骤:
1.定义一个类继承Thread。
2.重写run方法。
3.创建子类对象(创建线程对象)。
4.调用start方法,开启线程并让线程执行,同时还会告诉jvm去调用run方法。
  举例:

 1 //定义类MyThread继承Thread类
 2 public class MyThread extends Thread {
 3 @Override
 4 // 重写Thread类里的run方法
 5 public void run() {
 6 // 想要多线程执行的代码
 7 for (int i = 0; i < 100; i++) {
 8 // 获取线程名称和循环的次数
 9 System.out.println(getName() + " " + i);
10 }
11 }
12 }

主函数:

 1 public static void main(String[] args) {
 2 // 创建线程一
 3 MyThread myThread01 = new MyThread();
 4 // 为线程一设置线程名
 5 myThread01.setName("线程一");
 6 // 开启线程一
 7 myThread01.start();
 8 // 创建线程二
 9 MyThread myThread02 = new MyThread();
10 // 为线程二设置线程名
11 myThread02.setName("线程二");
12 // 开启线程二
13 myThread02.start();
14 }

三、Runnable接口

    JAVA实现多线程的另一种方法就是实现Runnable接口,实现 run 方法。然后创建Runnable的子类对象,
传入到某个线程的构造方法中,开启线程。Runnable接口其实就是用来指定每个线程要执行的任务,在由线
程类Thread来执行这些任务。Runnable接口只有一个要实现的方法:run(),作用与Thread类的run方法类似,
在启动该线程时将被调用,也就是说将由其实现类来实现run方法。Runnable接口的常用实现类是Thread类。
    B:创建线程的步骤:
1、定义类实现Runnable接口。
2、覆盖接口中的run方法。
3、创建Thread类的对象
4、将Runnable接口的子类对象作为参数传递给Thread类的构造函数。
5、调用Thread类的start方法开启线程。
  举例:

 1 //创建MyRunable类实现Runnable接口
 2 public class MyRunable implements Runnable {
 3 @Override
 4 //重写run方法
 5 public void run() {
 6 /*循环
 7 Thread.currentThread().getName:
 8 通过Thread类的静态方法currentThread()方法,返回正在执行的线程对象,并获取线程名*/
 9 for (int i = 0; i < 100; i++) {
10 System.out.println(Thread.currentThread().getName() + " :" + i);
11 }
12 }
13 }

  *主方法:

 1 public static void main(String[] args) {
 2 // 获取MyRunable对象(线程任务)
 3 MyRunable r = new MyRunable();
 4 // 根据线程任务创建线程一
 5 Thread t1 = new Thread(r);
 6 // 命名
 7 t1.setName("线程一");
 8 // 开启线程
 9 t1.start();
10 // 根据线程任务创建线程二
11 Thread t2 = new Thread(r);
12 t2.setName("线程二");
13 t2.start();
14 }

四、多线程安全

    由于CUP对线程的处理具有随机性,这就导致了当线程1进入某一循环,还没有执行循环里的语句时,
CUP突然切换到线程2,线程2也进入了循环语句。这样就会导致本应该只执行一次的条件执行了2次,导致
线程不安全的问题出现。
    问题出现的原因:
* 要有多个线程
* 要有被多个线程所共享的数据
* 多个线程并发的访问共享的数据。
  用实现Runnable接口的方式对同一数据进行

操作可能就会出现这种重复的问题:

 

(一)、多线程安全的解决

    问题出现了该如何解决呢?多线程处理的机制其实和我们在火车上厕所类似。在火车上有好多人都要去厕所,
但是厕所只能供一个人使用,2个人如果一起挤进了厕所就会发生一些“事情”,那么火车是怎么解决这个问题的呢?
我们可以在厕所的门上上一把锁,路人甲进厕所后把门锁起来,方便完之后再把锁打开,路人乙在进去把门锁上。
而JAVA为了解决多线程的并发安全问题,也给我们提供了这么一把“锁” - 同步代码块和同步方法。

1、同步代码块:

synchronized(锁对象){

}
  举例:

 1 public class MyRunable implements Runnable {
 2 // 设置一个被操作的数据
 3 int i = 100;
 4 
 5 @Override
 6 public void run() {
 7 while (true) {
 8 // 设置同步代码块
 9 synchronized (MyRunable.class) {
10 try {
11 // 为了不要太快,先睡一会
12 Thread.sleep(200);
13 } catch (InterruptedException e) {
14 // TODO Auto-generated catch block
15 e.printStackTrace();
16 }
17 // 对数据进行操作
18 if (i > 0) {
19 System.out.println(Thread.currentThread().getName() + " " + i--);
20 }
21 }
22 }
23 }
24 }

*入口方法:

 1 public static void main(String[] args) {
 2 MyRunable runable = new MyRunable();
 3 Thread t1 = new Thread(runable);
 4 t1.setName("线程A");
 5 Thread t2 = new Thread(runable);
 6 t2.setName("线程B");
 7 Thread t3 = new Thread(runable);
 8 t3.setName("线程C");
 9 t1.start();
10 t2.start();
11 t3.start();
12 }

    锁对象:可以是java中的任意对象。多个同步代码块必须使用同一个对象,才能实现多个代码块之间的同步。一
般使用当前类的.class对象

2、同步方法:

非静态方法:this
静态方法:字节码对象(类名.class)
  举例:

 1 public class MyRunable implements Runnable {
 2 // 设置一个被操作的数据
 3 int i = 100;
 4 
 5 public void run() {
 6 while (true) {
 7 method();
 8 }
 9 }
10 
11 private synchronized void method() {
12 
13 try {
14 Thread.sleep(150);
15 } catch (InterruptedException e) {
16 // TODO Auto-generated catch block
17 e.printStackTrace();
18 }
19 if (i > 0) {
20 System.out.println(Thread.currentThread().getName() + " :" + i);
21 i--;
22 }else {
23 System.exit(0);
24 }
25 }

  *入口方法:

 1 public static void main(String[] args) {
 2 MyRunable runable = new MyRunable();
 3 Thread t1 = new Thread(runable);
 4 t1.setName("线程A");
 5 Thread t2 = new Thread(runable);
 6 t2.setName("线程B");
 7 Thread t3 = new Thread(runable);
 8 t3.setName("线程C");
 9 t1.start();
10 t2.start();
11 t3.start();
12 }

3、优缺点

* 同步:安全性高,效率低。
* 非同步:效率高,但是安全性低。

五、使用多线程对同一数据进行不同的操作

  代码:

 1 public class Demo {
 2     public static class AddSub {
 3         //提供原子操作的Integer的类(无锁的线程安全整数 AtomicInteger)
 4         AtomicInteger at = new AtomicInteger(1);
 5         int j = 1;
 6 
 7         public static void main(String[] args) {
 8             AddSub ab = new AddSub();
 9             Add a = ab.new Add();
10             Sub b = ab.new Sub();
11             Thread t1 = new Thread(a);
12             Thread t2 = new Thread(a);
13             Thread t3 = new Thread(b);
14             Thread t4 = new Thread(b);
15             t1.start();
16             t2.start();
17             t3.start();
18             t4.start();
19         }
20 
21         public synchronized void add() {
22             j++;
23             System.out.println("add:" + j);
24         }
25 
26         public synchronized void sub() {
27             j--;
28             System.out.println("sub:" + j);
29         }
30 
31         class Add implements Runnable {
32             @Override
33             public void run() {
34                 for (int i = 0; i < 20; i++) {
35                     add();
36                 }
37 
38             }
39         }
40 
41         class Sub implements Runnable {
42             @Override
43             public void run() {
44                 for (int i = 0; i < 20; i++) {
45                     sub();
46                 }
47 
48             }
49         }
50     }
51 }

 

以上是关于JAVA基础-多线程的主要内容,如果未能解决你的问题,请参考以下文章

java基础入门-多线程同步浅析-以银行转账为样例

java多线程基础

Java基础之多线程

Java多线程基础

多线程编程学习一(Java多线程的基础)

Java 多线程基础多线程的实现方式