javaSE:不同方式线程创建;线程安全问题

目录

1、线程基本知识:

2、Thread方式创建线程

3、Runnable接口方式创建线程

4、线程安全问题

4.1、同步代码块

4.2、synchronized修饰

4.3、Lock锁


1、线程基本知识:

/*
 1、并发并行:
	并发:两个或多个事件在同一时间段内发生
		多个事件交替执行
	并行:两个或多个事件在同一时刻发生
		多个事件同时执行
			并行速度快些
 2、进程与线程:
	线程属于进程,是进程的一个执行单元,负责程序的执行
	进程:点击程序,会进入内存中占用内存执行,进入到内存的程序叫做进程
	线程:点击程序功能执行,就会开启一条应用程序到cpu的执行路径,cpu就可以通过这个路径执行功能,该路径叫线程。
		cpu:中央处理器,对数据进行计算,指挥电脑中的软硬件干活
		 分类:AMD
			  Inter Inter Core(核心) i7 8866 	4核心8线程
				8线程可以同时执行8个任务
		单核心单线程cpu:cpu在多个线程之间高速切换,轮流执行多个线程,效率低,切换速度(1/n毫秒)
		4核心8线程cpu:可以同时执行8个线程,8个线程在多个人物之间做高速的切换,速度是单线cpu的8倍(每个任务执行到的几率被提高8倍)
		
		多线程好处:1、效率高	2、多个线程之间互不影响
 3、线程调度:
		分时调度:所有线程轮流使用cpu的使用权,平均分配每个线程占用cpu的时间
		抢占式调度:优先让优先级高的线程使用cpu【抢占cpu占用时间】,如果线程优先级相同,那么随机选择一个线程。【java使用抢占式调度】
		
 4、主线程:
		执行主方法(main)的线程
		单线程程序:java程序中只有一个线程,执行从main方法开始,从上到下依次执行【出错后面就执行不了了】
		概念:JVM执行main方法进入到栈内存,JVM就会找操作系统开辟一条main方法通向cpu的执行路径,cpu就可以通过这个路径来执行main方法
																				这个路径就叫主(main)线程	
 */

2、Thread方式创建线程

/*
 创建多线程:
	方式1:
		创建Thread类的子类
		java.lang.Thread类,是描述线程的类
		实现:
			1、创建Thread类的子类
			2、在Thread的子类重写Thread类中的run方法,设置线程任务【开启线程要做什么】
			3、创建Thread类的子类对象
			4、调用Thread类的方法start方法,开启新的线程,执行run方法【中的任务】
			 public void start()使该线程开始执行;Java 虚拟机调用该线程的 run 方法。 
			 结果是两个线程并发地运行;当前线程(从调用返回给 start 方法)和创建的新线程(执行其 run 方法)。
			 多次启动一个线程是非法的。特别是当线程已经结束执行后,不能再重新启动。 
		java程序属于抢占式调度。
		主方法调用一次start()方法就是开辟新的栈空间,也就是增加一个线程,执行run()方法。多个线程互不影响。然后cpu就有了选择栈优先级的权利。
	
 */
 //方式1、
 public class Thread_lianxi extends Thread {
    @Override
    public void run() {
        for(int i=0;i<5;i++){
            System.out.println("run:"+i);
        }
    }
}
public class Thread_lianxi01 {
    public static void main(String[] args) {
        Thread_lianxi t=new Thread_lianxi();
        t.start();	//和直接调用run方法,是有区别的【直接调用run(),是一个单线程】
        for(int i=0;i<5;i++){
            System.out.println("main:"+i);
        }
    }
}
//java使用抢占式调度,优先级相同,所以随机选一个先执行
main:0
run:0
main:1
run:1
main:2
run:2
main:3
run:3
main:4
run:4
 /*
* 一、获取线程的名称:
*   1、获取Thread类中的方法 String getName()
*   2、可以先获取当前正在执行的线程,使用线程中的方法getName()获取线程名称
*           static Thread currentThread() 返回对当前正在执行的线程对象的引用。
  二、设置线程名称【了解】:
	1、使用Thread类中的setName(线程名字)		void setName(String name) 改变线程名称,使之与参数 name 相同。 
	2、创建一个带参数的构造方法,参数传递线程名称;调用父类的带参构造方法,把线程名称传递给父类,让父类给子线程起一个名字。
												Thread(String name) 	分配新的 Thread 对象。
												
												
* */
//一
public class Thread_lianxi02 extends Thread {
    @Override
    public void run() {
        //1
       // String name = getName();
        //System.out.println(name);//Thread-0   Thread-1

        Thread th=new Thread();
        System.out.println(th);//Thread[Thread-2,5,main]    Thread[Thread-3,5,main]

        String name = th.getName();
        System.out.println(name);//Thread-3 Thread-2
        //2 链式编程
        System.out.println(Thread.currentThread().getName());//
        //Thread-2 Thread-0

    }
}
public class Thread_lianxi03 {
    public static void main(String[] args) {
        Thread_lianxi02 t=new Thread_lianxi02();
        t.start();

        new Thread_lianxi02().start();

        System.out.println(Thread.currentThread().getName());
        //main
    }
}
==
//二、
public class MyThread_lianxi extends Thread {
    public MyThread_lianxi(){}
    public MyThread_lianxi(String name){
        super(name);//将线程名称传递给父类,让父类给子线程起一个名字
    }
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
 public class MyThread_lianxi01 {
    public static void main(String[] args) {
        MyThread_lianxi mt=new MyThread_lianxi();
        mt.setName("小强");
        mt.start();//小强

        new MyThread_lianxi("旺财").start();//旺财
    }
}

/*
	static void sleep(long millis) 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。 
		  */
public class sleep_lainxi {
    public static void main(String[] args) {
        for (int i = 0; i <=10; i++) {
            System.out.println(i);

            try {
                Thread.sleep(1000);//毫秒为单位 //【一秒打印一次i】
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

3、Runnable接口方式创建线程

/*创建多线程
	方式2:
		实现Runnable接口
		java.lang.Runable
			Runnable 接口应该由那些打算通过某一线程执行其实例的类来实现。类必须定义一个称为 run 的无参数方法。 
		java.lang.Thread类的构造方法:
			Thread(Runnable target)		分配新的 Thread 对象。 
			Thread(Runnable target, String name) 	分配新的 Thread 对象。 
		实现:			
			1、创建一个Runnable接口的实现类
			2、在实现类中重写Runnable接口的run方法,设置线程任务
			3、创建一个Runnable接口的实现类对象
			4、创建Thread类对象,构造方法中传递Runable接口的实现类对象
			5、调用Thread类中的start方法,开启新的线程执行run方法
实现Runnable接口创建多线程程序的好处:
	1、避免了单继承的局限性,一个类可以继承多个类
	2、降低了程序的耦合性,把设置线程任务和开启线程进行了分离(解耦)
		实现类中重写了run方法来设置线程任务;创建Thread类对象,开启了新的线程
		
*/
public class RunnableImpl implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i <= 5; i++) {
            System.out.print(Thread.currentThread().getName()+"-->"+i);
        }
    }
}
public class main {
    public static void main(String[] args) {
        RunnableImpl run=new RunnableImpl();
        Thread t=new Thread(run);
        t.start();

        for (int i = 0; i <= 5; i++) {
            System.out.print(Thread.currentThread().getName()+"-->"+i);
        }
    }
}//main-->0Thread-0-->0main-->1Thread-0-->1main-->2Thread-0-->2main-->3Thread-0-->3main-->4Thread-0-->4main-->5Thread-0-->5

4、线程安全问题

4.1、同步代码块

/*
1、同步代码块
	原理:同步代码块传入锁对象,同步中的进程抢到CPU执行权后获取锁对象并执行,执行完后归还锁,不执行完不会释放锁;
	同步外的线程就算抢到CPU执行权,没有锁对象也不会进入同步。
		格式:synchronized(锁对象){
			//可能出现线程安全的代码【共享数据的代码】
		}
	注意:1、通过代码块中的锁对象,可以使用任意对象
			2、但是必须保证多个线程使用的锁对象是同一个
			3、锁对象作用:
				把同步代码块锁住,只让一个线程在同步代码块中执行
	缺点:频繁的判断锁,获取锁,释放锁,程序效率会降低。
 */
public class RunnableImpl_01 implements Runnable {
    private int ticket=100;
    //创建一个锁对象
    Object obj=new Object();
    @Override
    public void run() {
     //使用死循环
        while(true){
            //创建同步代码块,让三个线程重复执行
            synchronized (obj){
                if(ticket>0){
                    //因为使共享数据,为了提高线程安全问题出现概率,让程序睡眠一下,此时线的程暂时失去程序的执行权
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket+"张票");
                    ticket--;
                }
            }
        }
     }
}
public class Ticket {
    public static void main(String[] args) {
        RunnableImpl_01 r=new RunnableImpl_01();
        Thread t0=new Thread(r);
        Thread t1=new Thread(r);
        Thread t2=new Thread(r);
        t0.start();
        t1.start();
        t2.start();
    }
}

4.2、synchronized修饰

/*2、同步方法:
	1、把访问了共享数据的代码抽取出来,放到一个方法中
	2、在方法上添加synchronized修饰符
	格式:定义方法的格式
	修饰符 synchronized 返回值类型 方法名(参数列表){
		访问了共享数据的代码
	}
	同步方法把方法里的代码锁住,只让一个线程执行;同步方法的锁对象是实现类对象r,也就是this
 */
 public class RunnableImpl_01 implements Runnable {
    private int ticket=100;
    @Override
    public void run() {
        while(true){
           payTicket();
            }
        }
        public synchronized void payTicket(){
            if(ticket>0){
                //因为使共享数据,为了提高线程安全问题出现概率,让程序睡眠一下,此时线程暂时失去程序的执行权
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket+"张票");
                ticket--;
            }
        }
     }
public class Ticket {
    public static void main(String[] args) {
        RunnableImpl_01 r=new RunnableImpl_01();
        Thread t0=new Thread(r);
        Thread t1=new Thread(r);
        Thread t2=new Thread(r);
        t0.start();
        t1.start();
        t2.start();
    }
}

4.3、Lock锁

/*3、Lock锁
	3.1 java.util.concurrent.locks  Lock接口
		方法:void lock() 获取锁。 
		      void unlock() 释放锁。
		java.util.concurrent.locks.ReentrantLock implements Lock接口
			使用步骤:1、在成员位置创建一个ReentrantLock对象
					2、在可能会出现安全问题的代码前调用Lock接口中的方法lock() 获取锁
					3、在可能会出现安全问题的代码后调用Lock接口中的方法unlock() 获取锁
 */
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class RunnableImpl_01 implements Runnable {
    private int ticket=100;
	//1
    Lock l=new ReentrantLock();

    @Override
    public void run() {
        while(true){
			//2
            l.lock();

            if(ticket>0){
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket+"张票");
                ticket--;
            }
			//3
            l.unlock();
            }
        }
     }
public class Ticket {
    public static void main(String[] args) {
        RunnableImpl_01 r=new RunnableImpl_01();
        Thread t0=new Thread(r);
        Thread t1=new Thread(r);
        Thread t2=new Thread(r);
        t0.start();
        t1.start();
        t2.start();
    }
}
==
/*
3.2 最典型的代码如下: 
 class X {
   private final ReentrantLock l = new ReentrantLock();
   // ...

   public void m() { 
     l.lock();  // block until condition holds
     try {
       // ... 无论程序是否异常都可以
     } finally {
       lock.unlock()
     }
   }
 }

 */
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class RunnableImpl_01 implements Runnable {
    private int ticket=100;
    Lock l=new ReentrantLock();

    @Override
    public void run() {
        while(true){
            l.lock();

            if(ticket>0){
                try {
                    Thread.sleep(10);
                    System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket+"张票");
                    ticket--;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally{
                    l.unlock();//无论程序是否异常,都会把锁释放
                }
            }
            }
        }
     }
public class Ticket {
    public static void main(String[] args) {
        RunnableImpl_01 r=new RunnableImpl_01();
        Thread t0=new Thread(r);
        Thread t1=new Thread(r);
        Thread t2=new Thread(r);
        t0.start();
        t1.start();
        t2.start();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值