一线程的概念
进程:是一个正在执行中的程序,每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元。
线程:就是进程中的一个独立的控制单元;线程在控制着进程的执行。
Java虚拟机启动的时候会有一个进程java.exe.该进程中至少一个线程负责java程序的执行。而且这个线程运行的代码存在于main方法中,该线程称之为主线程,每个进程中至少有一个线程。
二线程的创建
第一种方式:创建线程继承Thread类,
步骤:
1,定义类继承Thread。
2,复写Thread类中的run方法。
<wbr><wbr><wbr> 目的:定义自己的任务让线程驱动。<br>
3,调用线程的start方法,该方法两个作用:启动线程,调用run方法。<br>
如下代码:<br>
class MyThread extends Thread<br>
{<br><wbr><wbr><wbr> public void run()<br><wbr><wbr><wbr> {<br><wbr><wbr><wbr><wbr><wbr><wbr> for(int i=0; i<100; i++)<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr> System.out.println("Thread1 run----"+x);<br><wbr><wbr><wbr> }<br>
}<br>
class MyThreadDemo<br>
{<br><wbr><wbr><wbr> public static void main(String[] args)<br><wbr><wbr><wbr> {<br><wbr><wbr><wbr><wbr><wbr><wbr> //for(int x=0; x<4000; x++)<br><wbr><wbr><wbr><wbr><wbr><wbr> //System.out.println("Hello World!");<br><br><wbr><wbr><wbr><wbr><wbr><wbr> MyThread t = new MyThread();//创建好一个线程。<br><wbr><wbr><wbr><wbr><wbr><wbr> //t.start();//开启线程并执行该线程的run方法。<br><wbr><wbr><wbr><wbr><wbr><wbr> t.run();//仅仅是对象调用方法。而线程创建了,并没有运行。<br><br><wbr><wbr><wbr><wbr><wbr><wbr><br><wbr><wbr><wbr><wbr><wbr><wbr> for(int i=0; i<60; i++)<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr> System.out.println("Hello World!--"+i);<br><wbr><wbr><wbr><wbr><wbr><wbr> }<br>
}<br><wbr> 实现Runnable接口,实现接口里的run方法<br>
步骤:<br>
1,设计类实现Runnable接口实现该接口里的run方法;<br>
2,创建该类的是两年作为参数传如Thread类的构造方法;<br>
如下代码:<br>
class MyThread implements Runnable{<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr> public void run(){<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr> //这里定义自己的任务<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr> }<br>
}<br>
然后在创建启动线程<br>
new(new MyThread()).start();<br></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>
采用继承Thread类方式:
(1)优点:编写简单,如果需要访问当前线程,无需使用Thread.currentThread()方法,直接使用this,即可获得当前线程。
(2)缺点:因为线程类已经继承了Thread类,所以不能再继承其他的父类。
采用实现Runnable接口方式:
(1)优点:线程类只是实现了Runable接口,还可以继承其他的类。在这种方式下,可以多个线程共享同一个目标对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。
(2)缺点:编程稍微复杂,如果需要访问当前线程,必须使用Thread.currentThread()方法。
对象如同锁。持有锁的线程可以在同步中执行。
没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁。
最后总结一下单例设计模式:
懒汉设计模式如下:
class Single
{
<wbr><wbr><wbr> private static Single s = null;<br><wbr><wbr><wbr> private Single(){}<br><br><br><wbr><wbr> public static<wbr> Single getInstance()<br><wbr><wbr><wbr> {<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr> if(s==null)</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr> //--标记A<br></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr>s = new Single() ; <wbr><wbr><br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr> }<br><wbr><wbr><wbr><wbr><wbr><wbr> }<br><wbr><wbr><wbr><wbr><wbr><wbr> return s;<br><wbr><wbr><wbr> }</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>
采懒汉设计模式时候存在安全隐患,当线程执行到A处的时候执行权被剥夺了停了了下来此时另一个线程就可能执行到此处这样就可能创建多个Single对象引发错误;这种设计必须同步处理如下代码:
<wbr> public static<wbr> Single getInstance()<br><wbr><wbr><wbr> {<br><wbr><wbr><wbr><wbr><wbr><wbr> if(s==null)<br><wbr><wbr><wbr><wbr><wbr><wbr> {<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr> synchronized(Single.class)<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr> {<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr> if(s==null)<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr> s = new Single();<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr> }<br><wbr><wbr><wbr><wbr><wbr><wbr> }<br><wbr><wbr><wbr><wbr><wbr><wbr> return s;<br><wbr><wbr><wbr> }<br> }<br> 另外一种设计模式是饿汉式这种设计安全性比较高<br> class Single<br> {<br><wbr><wbr><wbr> private static final Single s = new Single();<br><wbr><wbr><wbr> private Single(){}<br><wbr><wbr><wbr> public static Single getInstance()<br><wbr><wbr><wbr> {<br><wbr><wbr><wbr><wbr><wbr><wbr> return s;<br><wbr><wbr><wbr> }<br> }</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>
四<wbr> 线程的安全问题的讨论与总结</wbr>
同步的前提:
1,必须要有两个或者两个以上的线程。
2,必须是多个线程使用同一个锁。
必须保证同步中只能有一个线程在运行。
好处:解决了多线程的安全问题。
弊端:多个线程需要判断锁,较为消耗资源
加锁对象是Object的实例;也可以通过加锁函数来实现同步此时的加锁对象是调用该函数的this,静态的同步方法,使用的锁是该方法所在类的字节码文件对象。类名.class,如下代码:
<wbr>多线程编程时候,常常出现错误的情况,这是由于系统线程调度有一定的随机性,所以我们必须对临界资源进行同步,下面是一个经典的例子银行取钱问题</wbr>
取钱的步骤:
1,用户输入帐号密码系统判断用户的账户密码是否匹配。
2,用户输入取款金额。
3,系统判断账户余额是否大于取款金额。
4,如果大于就成功否则就失败。
我们按上面的流程去编写取款程序,我们用两条线程来模拟取钱操作:
public class Account
{
<wbr><wbr><wbr> //封装账户编号、账户余额两个属性<br><wbr><wbr><wbr> private String accountNo;<br><wbr><wbr><wbr> private double balance;<br><wbr><wbr><wbr> public Account(){}<br><wbr><wbr><wbr> //构造器<br><wbr><wbr><wbr> public Account(String accountNo , double balance)<br><wbr><wbr><wbr> {<br><wbr><wbr><wbr><wbr><wbr><wbr> this.accountNo = accountNo;<br><wbr><wbr><wbr><wbr><wbr><wbr> this.balance = balance;<br><wbr><wbr><wbr> }<br><wbr><wbr><wbr> public void setAccountNo(String accountNo)<br><wbr><wbr><wbr> {<br><wbr><wbr><wbr><wbr><wbr><wbr> this.accountNo = accountNo;<br><wbr><wbr><wbr> }<br><wbr><wbr><wbr> public String getAccountNo()<br><wbr><wbr><wbr> {<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr>return this.accountNo;<br><wbr><wbr><wbr> }<br><br><wbr><wbr><wbr> public void setBalance(double balance)<br><wbr><wbr><wbr> {<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr>this.balance = balance;<br><wbr><wbr><wbr> }<br><wbr><wbr><wbr> public double getBalance()<br><wbr><wbr><wbr> {<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr>return this.balance;<br><wbr><wbr><wbr> }<br><br><br><wbr><wbr><wbr> //下面两个方法根据accountNo来计算Account的hashCode和判断equals<br><wbr><wbr><wbr> public int hashCode()<br><wbr><wbr><wbr> {<br><wbr><wbr><wbr><wbr><wbr><wbr> return accountNo.hashCode();<br><wbr><wbr><wbr> }<br><wbr><wbr><wbr> public boolean equals(Object obj)<br><wbr><wbr><wbr> {<br><wbr><wbr><wbr><wbr><wbr><wbr> if (obj != null<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr> && obj.getClass() == Account.class)<br><wbr><wbr><wbr><wbr><wbr><wbr> {<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr> Account target = (Account)obj;<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr> return target.getAccountNo().equals(accountNo);<br><wbr><wbr><wbr><wbr><wbr><wbr> }<br><wbr><wbr><wbr><wbr><wbr><wbr> return false;<br><wbr><wbr><wbr> }<br>
}<br>
接下来提供一个取钱的线程类,执行账户,取钱数量进行操作,逻辑是余额不足时候无法提取现金,当余额足够时候吐出钞票,余额减少。<br><br><br>
public class DrawThread extends Thread<br>
{<br><wbr><wbr><wbr> //模拟用户账户<br><wbr><wbr><wbr> private Account account;<br><wbr><wbr><wbr> //当前取钱线程所希望取的钱数<br><wbr><wbr><wbr> private double drawAmount;<br><br><wbr><wbr><wbr> public DrawThread(String name , Account account ,<br><wbr><wbr><wbr><wbr><wbr><wbr> double drawAmount)<br><wbr><wbr><wbr> {<br><wbr><wbr><wbr><wbr><wbr><wbr> super(name);<br><wbr><wbr><wbr><wbr><wbr><wbr> this.account = account;<br><wbr><wbr><wbr><wbr><wbr><wbr> this.drawAmount = drawAmount;<br><wbr><wbr><wbr> }<br><br><wbr><wbr><wbr> //当多条线程修改同一个共享数据时,将涉及到数据安全问题。<br><wbr><wbr><wbr> public void run()<br><wbr><wbr><wbr> {<br><wbr><wbr><wbr><wbr><wbr><wbr> //账户余额大于取钱数目<br><wbr><wbr><wbr><wbr><wbr><wbr> if (account.getBalance() >= drawAmount)<br><wbr><wbr><wbr><wbr><wbr><wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>