java基础-多线程
Java中的线程
在Java中,“线程”指两件不同的事情:
1、java.lang.Thread类的一个实例;
2、线程的执行。
在java中要想实现多线程,有两种手段,一种是继续Thread类,另外一种是实现Runable接口.(但是其实本质上都是通过Thread实现的
使用java.lang.Thread类或者java.lang.Runnable接口编写代码来定义、实例化和启动新线程。
一个Thread类实例只是一个对象,像Java中的任何其他对象一样,具有变量和方法,生死于堆上。
Java中,每个线程都有一个调用栈,即使不在程序中创建任何新的线程,线程也在后台运行着。
一个Java应用总是从main()方法开始运行,mian()方法运行在一个线程内,它被称为主线程。
一旦创建一个新的线程,就产生一个新的调用栈。
下面来看看第一种Thread方法创建
package Thread; public class Threadtest extends Thread{ @Override public void run(){ System.out.println("多线程的运行代码"); for(int i=0;i<6;i++) { System.out.println("这是多线程的逻辑代码代替实现"+i); } } }
package Thread; public class test { public static void main(String[] args) { Thread t0 = new Threadtest(); t0.start();//启动 System.out.println("---------"); System.out.println("---------"); System.out.println("---------"); } }
我们发现顺序不对!
原因是main方法即主线程执行t0.start多线程后,相当于在main方法之外开启一个支流
即t0.start()为一个分割线,在它之后的代码和run方法并行运行了就像两条支流。所以没有顺序,甚至多试几次还会出现--------------在中间等情况
而这就是多线程的异步性
。那么来看第二种创建方式过程(推荐)
package Thread; public class TestRunnable implements Runnable { @Override public void run() { System.out.println("Runnable多线程的运行代码"); for(int i=0;i<6;i++) { System.out.println("这是Runnable多线程的逻辑代码代替实现"+i); } } }
package Thread; public class test { public static void main(String[] args) { // Thread t0 = new Threadtest(); // t0.start();//启动 Thread t2 = new Thread(new TestRunnable()); //里面有一个Runnable对象 t2.start(); System.out.println("---------"); System.out.println("---------"); System.out.println("---------"); } }
当然Runnable不会这么简单
再来看一下加名字的变化
package Thread; public class TestRunnable implements Runnable { @Override public void run() { System.out.println(Thread.currentThread().getName()+"Runnable多线程的运行代码"); for(int i=0;i<6;i++) { System.out.println(Thread.currentThread().getName()+"这是Runnable多线程的逻辑代码代替实现"+i); } } }
package Thread; public class test { public static void main(String[] args) { // Thread t0 = new Threadtest(); // t0.start();//启动 Thread t2 = new Thread(new TestRunnable(),"t-2"); t2.start(); Thread t3 = new Thread(new TestRunnable(),"t-3"); t3.start(); System.out.println("---------"); System.out.println("---------"); System.out.println("---------"); } }
以上两个就是创建线程的过程和方式
1继承Thread类 重写run方法
2实现Runnable接口 实现run方法(推荐)
而实现run方法也好处更多
1因为继承了Thread就不能继承其他父类,不能再继承,(java的单继承原则)
2共享资源,多线程共享一个接口实现类的对象,可以多线程处理同一个资源。比如那一个count来计数
看例子
会发现count是共同的,并且还递增。
看完了上面之后再来了解一下同步与死锁的应用,思考一个问题
package ThreadTongbu; public class test { public static void main(String[] args) { //定义一个账户 Account a = new Account(); User u_weixin = new User(a,2000); User u_zhifubao = new User(a,2000); Thread weixin = new Thread(u_weixin,"微信"); Thread zhifubao = new Thread(u_zhifubao,"支付宝"); weixin.start(); zhifubao.start(); } } class Account{ public static int money = 3000; public void drawing(int m) { String name = Thread.currentThread().getName(); if(money<m) { System.out.println(name+"操作,账户余额不足"+money); } else { System.out.println(name + "操作,账户原有金额" + money); System.out.println(name + "操作,取款金额" + m); money = money - m; System.out.println(name + "操作,取款后的金额" + money); } } } class User implements Runnable{ Account account; int money; public User(Account account,int money){ this.account = account; this.money=money; } @Override public void run() { account.drawing(money); } }
发现钱甚至变负数了,说明线程同步的时候这样肯定不行。
所以需要线程同步与死锁
而也很简单只需要在方法上加上关键字即可
即我执行完了方法你再执行。
synchronized
就正常了
然后经过研究我们发现其实synchronized它锁的也可以是对象。
比如这样
这样每次可以锁不不同的对象,在多线程的时候因为会共用很多代码块数据等,这样也能完美避免,只针对不同的账户,不针对什么支付宝微信或者淘宝之类。
就会先支付宝再微信