——- android培训、java培训、期待与您交流! ———-
1,进程与线程:
进程是一个正在执行中的程序。每一个进程执行都有一个执行顺序,该顺序是一个执行路径或者叫一个控制单元。
线程就是进程中的一个独立的控制单元,线程在控制着进程的执行。
注意:jvm启动不止一个线程,除了主线程还有负责垃圾回收机制的线程。
2,创建线程的第一种方式:继承Thread类
(a)创建子类对象的同时就创建了线程,创建多少个子类对象就有多少条线程。
(b)步骤:
(1)定义类继承Thread。
(2)复写Thread类中的run方法。目的:将自定义代码存储在 run方法。让线程运行。
(3)调用线程的start方法。该方法两个作用:启动线程;调用 run方法。
(4)要是只调用run方法,这仅仅是调用对象的方法,而没有启动线程。
(c)多线程有一个特点:随机性。在互相抢夺cpu的执行权。
(d)线程都有自己默认的名称,Thread-编号 该编号从0开始。
static Thread currentThread():获取当前线程对象。
getName(): 获取线程名称。
设置线程名称:setName或者构造函数。
线程的状态图:
体现
public class Thread001 {
public static void main(String[] args) {
Deme d = new Deme();
d.start(); //开启线程
for (int i = 0; i < 60; i++) {//主线程
System.out.println("main::"+i);
}
}
}
class Deme extends Thread{ //继承Thread类
public void run(){ //自定义方法内容
for (int i = 0; i < 60; i++) {
System.out.println("Thread::"+i);
}
}
}
结果图:
3,创建线程的第二种方式:实现Runnable接口
步骤:
(a)定义类实现Runnable接口
(b)覆盖Runnable接口中的run方法。将线程要运行的代码存放在该run方法中。
(c)通过Thread类建立线程对象
(d)将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。因为自定义的run方法所属的对象是Runnable接口的子类对象,所以要让线程去指定对象的run方法。
Ticket类实现了Runnable接口
Ticket t=new Ticket();
Thread t1=new Thread(t)
4,实现方式和继承方式的区别
继承Thread:线程代码存放Thread子类run方法中。
实现Runnable:线程代码存放接口的子类的run方法。实现方式的好处是避免了单继承的局限性。
5,多线程的运行出现安全问题
(a)问题的原因
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程就参与进来执行,导致共享数据的错误。
体现:
public class Thread002 {
public static void main(String[] args) {
Ticket tick = new Ticket();
Thread d1 = new Thread(tick);
Thread d2 = new Thread(tick);
Thread d3 = new Thread(tick);
Thread d4 = new Thread(tick);
d1.start();//开启线程
d2.start();//开启线程
d3.start();//开启线程
d4.start();//开启线程
// new Thread(tick).start();
// new Thread(tick).start();
// new Thread(tick).start();
// new Thread(tick).start();
}
}
class Ticket implements Runnable{
private int tick = 100;
public void run() {
while (true) { //循环
if (tick>0) {
try {
Thread.sleep(10);//稍微等待
} catch (InterruptedException e) {
e.printStackTrace();//处理异常
}
System.out.println(Thread.currentThread().getName()+"....."+tick--);
}
}
}
}
结果图:
(b)解决办法
对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他线程不可以参与执行。
(c)多线程安全问题的解决办法是同步代码块:
synchronied(对象)
{需要被同步的代码}
对象如同锁。持有锁的线程可以在同步中执行,没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁。例如,火车上的卫生间。
(d)同步的前提:
(1)必须要有两个或者两个以上的线程。
(2)必须是多个线程使用同一个锁,必须保证同步中只能有一个线程在运行。
(e)同步的优劣性:
(1)解决了多线程的安全问题。
(2)需要判断锁,降低效率。
(f)同步函数的锁是synchronized(this);静态同步函数的锁是synchronized(类名.class)
(g)多线程的单例设计模式
懒汉式的特点是延迟加载实例,在多线程访问时,会出现安全问题,可以使用同步代码块或同步函数来解决,但比较低效,可以通过双重判断的形式来解决低效问题。同步所使用的锁是该类字节码文件对象。
体现:
//多线程单例设计模式—懒汉式
class S
{
private static S s=null;
private S (){};
public static S getIns ()
{
if(s==null)
{
synchronized(S.class)
{
if(s==null)
s=new S();
}
}
return s;
}
}
(h)死锁:同步中嵌套同步,使用不同的锁,万万不可。
体现:
class Test
{
public static void main(String[] args)
{
Thread t1 = new Thread(new Run(true));
Thread t2 = new Thread(new Run(false));
t1.start();
t2.start();
}
}
class Run implements Runnable
{
private boolean flag;
public Run(boolean flag)
{
this.flag = flag;
}
public void run()
{
if(flag)
{
synchronized(LockFactory.lockA)//同步锁A
{
System.out.println("if.....lockA");
synchronized(LockFactory.lockB)//同步锁B
{
System.out.println("if.....lockB");
}
}
}else
{
synchronized(LockFactory.lockB)//同步锁B
{
System.out.println("else...lockB");
synchronized(LockFactory.lockA)//同步锁A
{
System.out.println("else...lockA");
}
}
}
}
}
class LockFactory//用于提供锁的类
{
static LockA lockA = new LockA();
static LockB lockB = new LockB();
}
class LockA//锁A
{}
class LockB//锁B
{}
6,生产者与消费者的经典实例:
对于多个生产者和消费者,需要定义while判断标记。因为要让被唤醒的线程再一次判断标记。为什么定义notifyAll,因为需要唤醒对方线程。因为只用notify,容易出现只唤醒本方线程的情况。导致程序中的所有线程都等待。
毕老师视频中使用whlie,wait,notifyAll解决问题,我觉得在那个例子上只需改动判断条件即可实现。
体现:
public class Thread003 {
public static void main(String[] args) {
R r=new R();
P p = new P(r);
C c = new C(r);
Thread t1 = new Thread(p);
Thread t2 = new Thread(p);
Thread t3 = new Thread(c);
Thread t4 = new Thread(c);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class R{
private String name;
private int count = 1;
private boolean flag = true;
public synchronized void set(String name){
if (flag) {
this.name = name + "---" + count++;
System.out.println(Thread.currentThread().getName()+"...生产者..."+ this.name);
flag = false;
}
}
public synchronized void out(){
if (!flag) {
System.out.println(Thread.currentThread().getName()+"...消费者........"+this.name);
flag = true;
}
}
}
class P implements Runnable{
private R r;
P(R r){
this.r=r;
}
public void run() {
while (true) {
r.set("++商品++");
}
}
}
class C implements Runnable{
private R r;
C(R r){
this.r=r;
}
public void run(){
while (true) {
r.out();
}
}
}
7,JDK1.5升级
JDK1.5中提供了多线程升级解决方案,将同步Synchronized替换成显示的Lock操作。将Object中的wait,notify,notifyAll,替换了Condition对象:await(),signal(),signalAll()。
8,停止线程
定义循环结束标记:因为线程运行代码一般都是循环,只要控制了循环即可。
使用interrupt(中断)方法:该方法是结束线程的交结状态,使线程回到运行状态中来。
注:stop方法已经过时不再使用。
9,守护线程
setDaemon(boolean on),该方法必须在启动线程前调用。守护线程依赖于主线程,当主线程运行结束,守护线程也跟着结束。
Thread t=new Thread(d);
t.setDaemon(true);
t.start();
10,join()方法
当A线程执行到了B线程的.join()方法时,A就会等待,等B线程都执行完,A才会执行。join可以用来临时加入线程执行。
11,优先级
t1.setPriority(Thread.MAX_PRIORITY);最高优先级
t2.setPriority(Thread.MIN_PRIORITY);最低优先级
t3.setPriority(Thread.NORM_PRIORITY);默认优先级
786

被折叠的 条评论
为什么被折叠?



