Java学习笔记-7

Java学习笔记-7

一、基本概念

1.并发:同一时段交替执行
2.并行:同一时段同时执行
3.进程:进入到内存中的程序
4.线程:进程中的执行单元,是应用程序到CPU的执行路径,可以包含多个,
CPU执行时在多个线程之间高速切换,因此多核速度更快
5.主线程:JVM执行main方法时,main方法会进入栈内存,JVM会找操作系统开辟一条main方法通向CPU的路径供其执行,该路径即为主线程。单线程下主线程中执行时出现异常后续代码将不会执行,可以通过采用多线程来规避这一情况的出现


二、多线程

1.创建多线程程序

(1)创建Thread类的子类

1.创建Thread类的子类
2.重写run方法,设置线程任务
3.创建当前类对象
4.调用父类的start方法,开启新线程,执行run方法

先执行优先级高的线程,若优先级相同则随机选择一个执行

(2)使用Runnable接口实现类

1.创建Runnable接口实现类
2.重写run方法,设置线程任务
3.创建当前类对象
4.创建Thread类对象,参数为该接口实现类对象,调用start方法

(3)区别

1.实现Runnable接口可以再继承其它类或实现其它接口,避免了局限性

2.实现Runnable接口把设置线程任务和开启新线程进行分离(解耦)

2.获取线程名

1.Thread类中方法getName()

2.用currentThread()获取当前执行线程对象引用再调用getName()

3.设置线程名

1.Thread类中方法setName()

2.创建带参构造方法,调用父类带参构造方法,让父类给子类线程命名并分配Thread对象

4.暂停线程

sleep(long millis)

当前线程暂停相应毫秒数后继续执行

5.匿名内部类/接口实现类创建线程

package day6;

public class day6 {
    
    public static void main(String[] args) {

        MyThread myThread = new MyThread();

        myThread.setName("A");

        //开辟新的栈空间,执行栈方法
        //由于在不同栈空间,多线程中的异常并不会相互影响
        myThread.start();
        new MyThread("XXX").start();

        Impl impl = new Impl();
        new Thread(impl).start();

        //直接调用run还是单线程,仍然在main的栈空间中
//        myThread.run();

        for(int i = 0; i < 20; i++)
        {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("main:" + i);
        }

        //匿名内部类
        new Thread()
        {
            @Override
            public void run() {
                for(int i = 0; i < 20; i++)
                {
                    System.out.println(Thread.currentThread().getName() + " 匿名内部类 " + i);
                }
            }
        }.start();

        //匿名实现接口
        new Thread(new Runnable()
        {
            @Override
            public void run() {
                for(int i = 0; i < 20; i++)
                {
                    System.out.println(Thread.currentThread().getName() + " 匿名接口 " + i);
                }
            }
        }).start();
    }
}
package day6;

public class MyThread extends Thread {

    public MyThread(){}

    public MyThread(String name)
    {
        super(name);
    }
    
    @Override
    public void run() {
        for(int i = 0; i < 20; i++)
        {
            System.out.println("run:" + i);
        }

        String name = getName();
        System.out.println(name);

        Thread t = Thread.currentThread();
        System.out.println(t.getName());
    }
}
package day6;

public class Impl implements Runnable{

    @Override
    public void run() {
        for(int i = 0; i < 20; i++)
        {
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
    }
}

三、线程安全

1.线程安全问题产生情况

	private int ticket = 100;

    @Override
    public void run() {

        while (true)
        {
            if(ticket > 0)
            {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "-->第" + ticket + "张票");
                ticket--;
            }
        }

    }
		Runnable run = new RunnableImpl();

        Thread thread1 = new Thread(run);
        Thread thread2 = new Thread(run);
        Thread thread3 = new Thread(run);
        thread1.start();
        thread2.start();
        thread3.start();

三个线程抢夺CPU执行权,在sleep处失去执行权,这时判断条件(ticket数量)会因为其它线程执行而改变,判断条件在不一定成立的情况下向后执行,出现线程安全问题

解决思路:在一个线程涉及到访问共享数据时,不管是否失去执行权其它线程必须等待

2.线程同步

解决访问共享资源时产生的线程安全问题

(1)同步代码块

synchronized同步使相应区块资源实行互斥访问

synchronized(锁对象)
{
	//需要同步操作的代码
}

锁对象可以是任意对象,只需保证每个线程均使用同一对象即可(也就是放在方法外面声明)

锁对象只允许一个线程在同步代码块中执行

		while (true)
        {
            synchronized (obj)
            {
                if(ticket > 0)
                {
                    try {
                        Thread.sleep(10);
                    }
                    catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "-->第" + ticket + "张票");
                    ticket--;
                }
            }
        }

原理:执行到synchronized代码块时会检查是否有锁对象,如果有则获取并执行,没有就阻塞,执行完归还(这就是为什么锁对象只能有一个)

(2)同步方法
public synchronized void method(){}

把访问共享数据的代码放进去即可

	@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--;
        }
    }

原理是一样的,只不过锁对象换成了this(线程实现类对象)

(3)静态同步方法

将方法和相关变量声明为静态也可实现同步,此时锁对象是实现类的class文件对象(如RunnableImpl.class)

(4)Lock锁
//获取锁
void lock();
//释放锁
void unlock();

创建一个ReentrantLock(Lock接口实现类)对象,在可能产生安全问题的代码前后分别调用lock和unlock

	ReentrantLock lock = new ReentrantLock();

	@Override
    public void run() {

        while (true)
        {
            lock.lock();
            if(ticket > 0)
            {
                try {
                    Thread.sleep(10);
                }
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "-->第" + ticket + "张票");
                ticket--;
            }
            lock.unlock();
        }
    }

考虑到总是要释放锁的,为了提高效率,更好的写法是:

		while (true)
        {
            lock.lock();
            if(ticket > 0)
            {
                try {
                    Thread.sleep(10);
                    System.out.println(Thread.currentThread().getName() + "-->第" + ticket + "张票");
                    ticket--;
                }
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
                finally 
                {
                    lock.unlock();
                }
            }
        }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值