------- android培训、java培训、期待与您交流! ----------
多线程算是Java中比较重要的一个部分了,下面把个人觉得的一些重要内容和大家分享下~~
概述
进程:正在执行中的程序
线程:进程中一个负责程序执行的控制单元(执行路径)。
P.S.
1、一个进程中可以有多个执行路径,称之为多线程。
2、一个进程中至少要有一个线程。
多线程的好处:解决了多部分代码同时运行的问题。
多线程的弊端:线程太多,会导致效率的降低。
其实,多个应用程序同时执行都是CPU在做着快速的切换完成的。这个切换是随机的。CPU的切换是需要花
费时间的,从而导致了效率的降低。————>多线程的实质(⊙o⊙)哦。
在单线程程序中,只有上一句代码执行完,下一句代码才有执行的机会。
如何定义一个线程?
创建线程方式一:继承Thread类
1.定义一个类继承Thread类。
2.覆盖Thread类中的run方法。
3.直接创建Thread的子类对象创建线程。
4.调用start方法开启线程并调用线程的任务run方法执行。
run方法中定义的就是线程要运行的任务代码。
P.S.
继承Thread类的类对象调用start方法开启了线程,并执行线程的run方法;
而直接调用run方法,仅仅是对象调用方法,没有新线程开启;
创建线程方式二:实现Runnable接口
1.定义类实现Runnable接口。
2.覆盖接口中的run方法,将线程的任务代码封装到run方法中。
3.通过Thread类创建线程对象,并将Runnable接口的子类对象作为Thread类的构造函数的参数进行传递。
4.调用线程对象的start方法开启线程。
方式二更为常用~~(Java中是单继承,使用方式二避免了Java单继承的局限性。)
其实下面才是重点——多线程的安全性
问题的原因:
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,
另一个线程参与进来执行。导致共享数据的错乱。
解决办法:
对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他线程不可以参与执行。
在java中,用同步代码块就可以解决这个问题。
同步代码块的格式:
synchronized(对象){
需要被同步的代码;其实就是操作共享数据的语句
}
对象如同锁。持有锁的线程可以在同步中执行。没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁。
同步的好处:解决了线程的安全问题。
同步的弊端:当线程相当多时,因为每个线程都会去判断同步上的锁,无形中会降低程序的运行效率。
同步的前提:必须有多个线程并使用同一个锁。
当synchronized出现在函数声明上,函数就具备了同步性(同步函数)
利用同步代码块解决安全问题案例:
/*
需求:
银行有一个金库。
有两个储户分别存300元,每次存100,存3次。
如何找问题:
1,明确哪些代码是多线程运行代码。
2,明确共享数据。
3,明确多线程运行代码中哪些语句是操作共享数据的。
*/
class Bank
{
private int sum;//金库金额
public void add(int n)
{
synchronized(this)
{
sum = sum + n;
System.out.println("sum="+sum);
}
}
}
class ChuHu implements Runnable
{
private Bank b = new Bank();
public void run()//储户向金库存钱
{
for(int x=0; x<3; x++)
{
b.add(100);
}
}
}
class BankDemo
{
public static void main(String[] args)
{
ChuHu c = new ChuHu();
Thread t1 = new Thread(c);
Thread t2 = new Thread(c);
t1.start();
t2.start();
}
}
同步函数和同步代码块的区别:
1.同步函数的锁是固定的this。
2.同步代码块的锁是任意的对象。
静态的同步函数使用的锁是该函数所属字节码文件对象,可以用当前类名.class表示。
总结完各种同步后,提醒各位小心死锁(同步中嵌套同步,但个同步中锁不一样)
上个死锁的例子,小心避免啊
class Test implements Runnable
{
private boolean flag;//标记位,好让下面出现死锁
Test(boolean flag)
{
this.flag = flag;//两线程创建时传入不同标记
}
public void run()
{
if(flag)//标记位true的到这来
{
while(true)
{
synchronized(MyLock.locka)//持有locka
{
System.out.println(Thread.currentThread().getName()+"...if locka ");
synchronized(MyLock.lockb)//标记位false的线程持有lockb时,这里就停住进不去了
{
System.out.println(Thread.currentThread().getName()+"..if lockb");
}
}
}
}
else//标记位false的
{
while(true)
{
synchronized(MyLock.lockb)//持有lockb
{
System.out.println(Thread.currentThread().getName()+"..else lockb");
synchronized(MyLock.locka)//当上面的持有locka这里就停这了
{
System.out.println(Thread.currentThread().getName()+".....else locka");
}
}
}
}
}
}
//封装两个锁方便使用
class MyLock
{
static Object locka = new Object();
static Object lockb = new Object();
}
class DeadLockTest
{
public static void main(String[] args)
{
Thread t1 = new Thread(new Test(true));
Thread t2 = new Thread(new Test(false));
t1.start();
t2.start();
}
}
额,先到这里,下回在更