首页 > 编程语言 > 详细

JAVA学习(多线程创建的两种方法,多线程安全隐患)

时间:2021-04-01 00:40:51      阅读:14      评论:0      收藏:0      [点我收藏+]

一、多线程创建

进程:是系统进行资源分配和调度的基本单位,可以理解为进程是正在运行的程序的实例。

线程:是操作系统能够进行运算调度的最小单位,是进程中的实际运作单位,每个线程都有自己运行的内容,这个内容可以称为线程要执行的任务,一个进程可以并发执行多个线程,

 

JVM创建的主线程的任务都定义在了主函数main中,

 

创建执行线程有两种方法:

方式一:继承Thread类

  自定义的线程使用Thread类,Thread类用于描述线程,线程需要任务,所以Thread类也对任务进行描述,这个任务使用Thread类中的run方法实现,也就是说,run方法就是封装自定义线程运行任务的函数。

1.定义一个类继承Thread类。

2.覆盖Thread类中的run方法。

3.直接创建Thread类的子类对象来创建线程。

4.调用start方法开启线程并调用线程的任务run方法执行。

例如:

public class Demo extends Thread{
    private String name;
    Demo(String name){
        this.name = name;
    }
    public void run(){
        for (int x=0 ; x<10 ;x++){
            for (int i = -9999999;i<999999;i++){}
            System.out.println(name+"....x = "+x);
        }
    }
}

public class ThreadDemo {
    public static void main(String[] args) {
        Demo d1 = new Demo("旺财");
        Demo d2 = new Demo("小红");
        d1.start();
        d2.start();
    }
}

运行结果:

技术分享图片

 

线程的四种状态:

 技术分享图片

 

 

 

方式二:扩展类的功能,通过接口的形式完成,实现Runnable接口

1.定义实现Runnable接口。

2.覆盖接口中的run方法,将线程的任务代码封装到run方法中。

3.通过Thread类创建线程对象,并将Runnable接口的子类对象作为Thread类的构造函数的参数进行传递。

因为线程的任务都封装在Runnable接口子类对象的run方法中,所以要在线程对象创建时就明确要运行的任务。

4.调用线程对象的start方法开启线程。

实现Runnable接口的优点:

1.将线程的任务从线程的子类中分离出来,进行了单独的封装。

按照面向对象的思想将任务封装成对象。

2.避免了JAVA单继承的局限性。

例如:

public class Demo implements Runnable{
    public void run(){
        show();
    }
    public void show(){
        for(int x=0;x<10;x++){
            System.out.println(Thread.currentThread().getName()+"....x="+x);
        }
    }
}

public class ThreadDemo {
    public static void main(String[] args) {
        Demo d = new Demo();
        Thread t1 = new Thread(d);   //参数d为run方法被调用的对象  
        Thread t2 = new Thread(d);
        t1.start();
        t2.start();
    }
}

运行结果:

技术分享图片

 

二、多线程的安全隐患

一块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源;
比如多个线程访问同一个对象、同一个变量、同一个文件;
当多个线程访问同一块资源时,很容易引发 数据错乱和数据安全问题。
 
产生原因:
1.多个线程在操作共享的数据。
2.操作共享数据的线程代码有多条。
 
当线程在执行操作共享数据的多条代码过程中,其他线程参与了运算,就会导致线程安全的产生。
 
解决方法:使用同步代码块
将多条操作共享数据的线程代码封装起来,当有线程执行这些代码的时候,其它线程此时不可以参与运算。
必须要当前线程把这些代码都执行完毕后,其他线程才可以参与运算。
 
同步代码块格式:
synchronized(对象){
      //需要同步的代码;
}
 
好处:解决了线程的安全问题。
弊端:想对降低了效率,因为同步外的线程都会判断同步锁。
 
例如:
 
public class Ticket implements Runnable{
    private int num = 100;
    Object obj = new Object();
    public  void run(){
        for(int x=-999999999;x<999999999;x++){}
        synchronized (obj){     
            while(true){
                if(num>0){
                    System.out.println(Thread.currentThread().getName()+"...sale..."+num--);
                }
                else{
                    break;
                }
            }
        }

    }
}


public class TicketDemo {
    public static void main(String[] args) {
        Ticket t = new Ticket();

        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        Thread t3 = new Thread(t);
        Thread t4 = new Thread(t);

        t1.start();
        t2.start();
        t3.start();
        t4.start();

    }
}

 

 

JAVA学习(多线程创建的两种方法,多线程安全隐患)

原文:https://www.cnblogs.com/gmangofight/p/14602919.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!