多线程学习(一)


前言

  无论是学习还是找工作,多线程都是重点,今天在这里分享一些多线程的基本知识,希望大家跟我一起学习。


一、进程跟线程有什么区别?

  在学习多线程之前,我们需要弄清楚几个概念,什么是进程?什么是线程?这两者有什么区别跟联系?

  • 进程是指正在运行的程序,它是程序运行和资源分配的基本单位,一个程序至少有一个进程,一个进程至少有一个线程;
  • 线程是CPU调度和分派的基本单位,是可以独立运行的基本单位,同一进程中的多个线程可以并发执行;
  • 进程在执行过程中拥有独立的内存单元,而多个线程共享内存单元,减少切换次数,从而效率更高。

二、如何创建线程?

1.继承Thread类

  创建线程的第一种方式就是继承Thread类,并重写run()方法,创建一个子类对象,子类对象通过调用start()方法启动线程。注意,启动线程使用start()方法,而不是直接调用run()方法,直接调用就和普通方法一样。代码演示如下:

public class Thread01 {

    public static void main(String[] args) {

        MyThread01 t1 = new MyThread01();
        MyThread02 t2 = new MyThread02();
        t1.setName("线程一");
        t2.setName("线程二============");
        t1.start();
        t2.start();
    }

}
class MyThread01 extends Thread {

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

class MyThread02 extends Thread {

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

运行结果如下:
在这里插入图片描述

2.实现Runnable接口

  在java中,一个类只可以继承父类,但是可以实现多个接口,如果某一个类已经继承了其他类就无法通过继承Thread类来创建线程,这个时候我们可以通过实现Runnable接口,然后重写run()方法,创建一个子类对象,并将此对象作为参数来创建一个Thread类的对象,然后通过start()方法开始线程。代码演示如下

public class Thread02 {

    public static void main(String[] args) {
        MyThread03 myThread03 = new MyThread03();
        Thread t3 = new Thread(myThread03);
        MyThread04 myThread04 = new MyThread04();
        Thread t4 = new Thread(myThread04);
        t3.setName("线程3");
        t4.setName("线程4============");
        t3.start();
        t4.start();
    }

}

class MyThread03 implements Runnable {
    
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            if (i % 2 == 0) {
                System.out.println(Thread.currentThread().getName() + "=" + i);
            }
        }
    }
}

class MyThread04 implements Runnable {
    
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            if (i % 2 == 0) {
                System.out.println(Thread.currentThread().getName() + "=" + i);
            }
        }
    }
}

运行结果如下:
在这里插入图片描述

3.实现Callable接口

  Java5.0在Java.util.concurrent提供了一个新的创建执行线程的方式:实现Callable接口,并重写call()方法,大家要注意,这次不是重写run()方法,而是带有返回值的call()方法,需要借助FutureTask类来开启线程和获取返回结果。关于Future接口以及它的唯一实现类的说明放在代码注释中,具体代码实现如下:

/**
Future接口可以对具体Runnable、Callable任务的执行结果进行取消、查询是否完成、获取结果等;
FutureTask是Futrue接口的唯一的实现类;
FutureTask 同时实现了Runnable, Future接口;
它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值。
*/
public class Thread03 {

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        MyThread05 myThread05 = new MyThread05();
        MyThread06 myThread06 = new MyThread06();
        FutureTask<Integer> futureTask5 = new FutureTask<Integer>(myThread05);
        FutureTask<Integer> futureTask6 = new FutureTask<Integer>(myThread06);
        Thread thread5 = new Thread(futureTask5, "方式5");
        Thread thread6 = new Thread(futureTask6, "方式6=======");
        thread5.start();
        thread6.start();
        System.out.println("方式5的和" + futureTask5.get());
        System.out.println("方式6的和" + futureTask6.get());
    }
}

class MyThread05 implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for(int i = 0; i < 10; i++) {
            if(i % 2 == 0) {
                System.out.println(Thread.currentThread().getName() + "=" + i);
                sum += i;
            }
        }
        return sum;
    }
}

class MyThread06 implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for(int i = 0; i < 10; i++) {
            if(i % 2 != 0) {
                System.out.println(Thread.currentThread().getName() + "=" + i);
                sum += i;
            }
        }
        return sum;
    }
}

运行结果如下:
在这里插入图片描述

4.通过线程池创建线程

  线程池在下一篇博客详细说明,代码如下:

public class Thread04 {

    public static void main(String[] args) {
        //线程池
        ExecutorService pool = Executors.newFixedThreadPool(10);

        ThreadPoolExecutor executor = (ThreadPoolExecutor) pool;
        //开启线程
        MyThread07 myThread07 = new MyThread07();
        MyThread07 myThread08 = new MyThread07();

        executor.execute(myThread07);
        executor.execute(myThread08);
    }

}

class MyThread07 implements Runnable{

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

}

运行结果如下:
在这里插入图片描述

三、线程有哪几种状态?

  线程是一个动态执行的过程,它也有一个从产生到死亡的过程。下图显示了一个线程完整的生命周期。
在这里插入图片描述

四、什么是线程不安全?

  线程不安全是指不提供加锁保护机制保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据。举个例子,售票系统有100张票,A和B同时来买票,如果线程不安全,就会发生100-1这个操作,同时执行,结果就是A和B都买到票了,然后系统中余票显示还有99张。代码演示如下:

public class Thread05 {
    public static void main(String[] args) {
        Count count = new Count();
        Thread t1 = new Thread(count,"线程1======");
        Thread t2 = new Thread(count,"线程2");
        t1.start();
        t2.start();
    }
}

class Count implements Runnable {

    private int count = 100;
    
    @Override
    public void run() {

        while (true) {
            if (count == 0) {
                break;
            }
            try {
            	//增加出现线程不安全情况的几率,为了演示方便
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            count--;
            System.out.println(Thread.currentThread().getName() + "(" + count + ")");
        }
    }
}

运行结果如下:
在这里插入图片描述
那么要如何解决呢?可以采用加锁保护机制,代码如下:

public class Thread06 {
    public static void main(String[] args) {
        Count1 count = new Count1();
        Thread t1 = new Thread(count, "线程1======");
        Thread t2 = new Thread(count, "线程2");
        t1.start();
        t2.start();
    }
}

class Count1 implements Runnable {
    private int count = 100;

    @Override
    public void run() {

        while (true) {
            synchronized (this) {
                if (count == 0) {
                    break;
                }
                try {
                    //增加出现线程不安全情况的几率,为了演示方便
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                count--;
                System.out.println(Thread.currentThread().getName() + "(" + count + ")");
            }
        }
    }
}

使用synchronized 关键字将售票这个过程“锁”起来,就不会造成两个人都买到票,但是票数只减了一张这种情况的发生。运行结果如下:
在这里插入图片描述

五、线程的常用方法?

下面列举一些Thread类的实例对象的一些重要方法

方法名方法描述
start()使该线程开始执行;Java 虚拟机调用该线程的 run 方法。
run()如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。
setName(String name)改变线程名称,使之与参数 name 相同。
setPriority(int priority)更改线程的优先级。
setDaemon(boolean on)将该线程标记为守护线程或用户线程。
join(long millisec)等待该线程终止的时间最长为 millis 毫秒。
interrupt()中断线程。
isAlive()测试线程是否处于活动状态。

下面列举一些Thread类的一些静态方法

静态方法名方法描述
yield()暂停当前正在执行的线程对象,并执行其他线程。
sleep(long millisec)在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)
holdsLock(Object x)当且仅当当前线程在指定的对象上保持监视器锁时,才返回 true。
currentThread()返回对当前正在执行的线程对象的引用。
dumpStack()将当前线程的堆栈跟踪打印至标准错误流。

总结

Good Good Study,Day Day Up!

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
Python多线程是一种并发编程技术,可以同时执行多个线程,以提高程序的运行效率。在Python中,可以使用`threading`模块来实现多线程。 下面是一个简单的Python多线程示例: ```python import threading def worker(): print("Worker is running") # 创建线程对象 thread1 = threading.Thread(target=worker) thread2 = threading.Thread(target=worker) # 启动线程 thread1.start() thread2.start() # 等待所有线程结束 thread1.join() thread2.join() ``` 在上面的示例中,我们定义了一个`worker`函数,它会在控制台输出一条消息。然后我们创建了两个线程对象,并使用`start()`方法启动它们。最后,我们使用`join()`方法等待所有线程结束。 需要注意的是,多线程在Python中并不一定能够实现真正的并行执行,因为Python的GIL(全局解释器锁)机制限制了多线程的执行效率。这意味着即使在多个线程中同时执行相同的代码,也只有一个线程可以获得CPU资源进行执行。但是,Python多线程对于某些特定的任务仍然是非常有用的,例如I/O密集型任务或者使用多核CPU的系统。 在Python中学习线程时,需要了解以下几点: 1. 线程的创建和启动:需要使用`Thread`类来创建线程对象,并使用`start()`方法来启动线程。 2. 线程的同步:由于GIL机制的存在,Python多线程并不能实现真正的并行执行。因此,需要使用锁、条件变量等机制来保证线程之间的同步和通信。 3. 线程池:可以使用线程池来管理多个线程,以提高程序的运行效率。Python中的`queue`模块提供了线程安全的队列,可以用于实现线程池。 4. 多进程:如果需要更高效的并发编程,可以使用Python的多进程模块`multiprocessing`。它可以更好地利用多核CPU的优势,并避免GIL的影响。 5. 锁的使用:在使用多线程时,需要使用锁来保证线程之间的同步和通信。需要注意避免死锁和竞争条件等问题。 6. 死锁问题:死锁是线程之间相互等待资源导致的问题,可以通过适当的调度策略和使用锁来避免死锁问题的发生。 7. 多线程的优点和缺点:多线程适用于I/O密集型任务和需要并发执行的任务。但是,它也存在一些缺点,如性能开销、资源竞争等问题。需要根据具体的应用场景来选择是否使用多线程。 总之,Python多线程是一种重要的并发编程技术,可以用于提高程序的运行效率。在学习Python多线程时,需要了解其基本原理和常见问题,并根据具体的应用场景来选择是否使用多线程。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值