• 3个售票员,卖30张票
 
package com.javase.thread;
 
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
 
class Ticket {
 
     private int number = 30;
     private Lock lock = new ReentrantLock();
 
     public void sale() {
 
           lock.lock();
           try {
                if(number > 0) {
                     Thread.sleep(300);
                     System.out.println(Thread.currentThread().getName() + "卖出第" + (number--) + "张票,还剩" + (number)+"张票。");
                }
           } catch (Exception e) {
                e.printStackTrace();
           } finally {
                lock.unlock();
           }
     }
 
}
 
/**
 * 3个售票员,卖30张票
 * @author Bo
 *
 */
public class ThreadDemo0 {
 
     public static void main(String[] args) {
           final Ticket ticket = new Ticket();
 
           new Thread(new Runnable() {
                public void run() {
                     for (int i = 0; i < 40; i++) {
                           ticket.sale();
 
                     }
                }
           },"AA").start();
           new Thread(new Runnable() {
                public void run() {
                     for (int i = 0; i < 40; i++) {
 
                           ticket.sale();
                     }
                }
           },"BB").start();
           new Thread(new Runnable() {
                public void run() {
                     for (int i = 0; i < 40; i++) {
 
                           ticket.sale();
                     }
                }
           },"CC").start();
     }
}
  • Callable接口
 
package com.javase.thread;
 
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
 
class Thread1 implements Runnable{
 
     @Override
     public void run() {
           System.out.println("runable come in...");
     }
 
}
 
class Thread2 implements Callable<Integer> {
 
     private int number = 30;
 
     @Override
     public Integer call() throws Exception {
 
           if(number > 0) {
                System.out.println(Thread.currentThread().getName() + "在卖第" + number-- + "还剩" + number+"张票。");
           }
           return 200;
     }
 
}
 
public class ThreadDemo1 {
 
     public static void main(String[] args) {
 
           FutureTask<Integer> futureTask = new FutureTask<Integer>(new Thread2());
 
           new Thread(futureTask).start();
           try {
                System.out.println(futureTask.get());
           } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
           }
 
     }
}
 
  • 题目:现在两个线程,可以操作同一个变量,实现一个线程对该变量加1,一个线程对该变量减1, 实现交替,来10轮,变量初始值为零。
 
方法①:使用的同步锁synchronized
package com.javase.thread;
 
class ShareData {
 
     int number = 0;
 
     public synchronized void increment() {
 
           while (number != 0) {//这里要用while,因为使用if,会造成几个线程同时运行。
                try {
                     wait();
                } catch (InterruptedException e) {
                     e.printStackTrace();
                }
           }
           ++number;
           System.out.println(Thread.currentThread().getName() +"\t"+ number);
           notifyAll();
 
     }
 
     public synchronized void decrement() {
 
           while (number == 0) {
                try {
                     wait();
                } catch (InterruptedException e) {
                     e.printStackTrace();
                }
           }
           --number;
           System.out.println(Thread.currentThread().getName() +"\t"+ number);
           notifyAll();
     }
}
 
/**
 * 题目:现在两个线程,可以操作同一个变量,实现一个线程对该变量加1,一个线程对该变量减1, 实现交替,来10轮,变量初始值为零。
 *
 * @author Bo
 *
 */
public class ThreadDemo2 {
 
     public static void main(String[] args) {
 
           final ShareData shareData = new ShareData();
 
           new Thread(new Runnable() {
                public void run() {
                     for (int i = 0; i < 10; i++) {
                           try {
                                Thread.sleep(200);
                           } catch (InterruptedException e) {
                                e.printStackTrace();
                           }
                           shareData.increment();
 
                     }
                }
           },"AA").start();
 
           new Thread(new Runnable() {
                public void run() {
                     for (int i = 0; i < 10; i++) {
                           try {
                                Thread.sleep(300);
                           } catch (InterruptedException e) {
                                e.printStackTrace();
                           }
                           shareData.decrement();
 
                     }
                }
           },"BB").start();
           new Thread(new Runnable() {
                public void run() {
                     for (int i = 0; i < 10; i++) {
                           try {
                                Thread.sleep(400);
                           } catch (InterruptedException e) {
                                e.printStackTrace();
                           }
                           shareData.increment();
 
                     }
                }
           },"CC").start();
 
           new Thread(new Runnable() {
                public void run() {
                     for (int i = 0; i < 10; i++) {
                           try {
                                Thread.sleep(500);
                           } catch (InterruptedException e) {
                                e.printStackTrace();
                           }
                           shareData.decrement();
 
                     }
                }
           },"DD").start();
     }
}
方法②:使用lock
 
package com.javase.thread;
 
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
 
class ShareData_2 {
     private int number = 0;
     private Lock lock = new ReentrantLock();
     private Condition condition = lock.newCondition();
 
     public void increment() {
 
           lock.lock();
           try {
                while (number != 0) {
                     condition.await();
                }
                ++number;
                System.out.println(Thread.currentThread().getName() +"\t"+ number);
                condition.signalAll();
 
           } catch (Exception e) {
                e.printStackTrace();
           } finally {
                lock.unlock();
           }
     }
 
     public void decrement() {
           lock.lock();
           try {
                while(number == 0) {
                     condition.await();
                }
                --number;
                System.out.println(Thread.currentThread().getName() +"\t"+ number);
                condition.signalAll();
           } catch (Exception e) {
                e.printStackTrace();
           } finally {
                lock.unlock();
           }
     }
}
 
/**
 * 题目:现在两个线程,可以操作同一个变量,实现一个线程对该变量加1,一个线程对该变量减1, 实现交替,来10轮,变量初始值为零。 方法2:使用lock
 *
 * @author Bo
 *
 */
public class ThreadDemo2_2 {
 
     public static void main(String[] args) {
 
           final ShareData_2 data_2 = new ShareData_2();
           new Thread(new Runnable() {
                public void run() {
                     for (int i = 0; i < 10; i++) {
                           try {
                                Thread.sleep(200);
                           } catch (InterruptedException e) {
                                e.printStackTrace();
                           }
                           data_2.increment();
                     }
                }
           },"AA").start();
           new Thread(new Runnable() {
                public void run() {
                     for (int i = 0; i < 10; i++) {
                           try {
                                Thread.sleep(300);
                           } catch (InterruptedException e) {
                                e.printStackTrace();
                           }
                           data_2.decrement();
                     }
                }
           },"BB").start();
           new Thread(new Runnable() {
                public void run() {
                     for (int i = 0; i < 10; i++) {
                           try {
                                Thread.sleep(300);
                           } catch (InterruptedException e) {
                                e.printStackTrace();
                           }
                           data_2.increment();
                     }
                }
           },"CC").start();
           new Thread(new Runnable() {
                public void run() {
                     for (int i = 0; i < 10; i++) {
                           try {
                                Thread.sleep(400);
                           } catch (InterruptedException e) {
                                e.printStackTrace();
                           }
                           data_2.decrement();
                     }
                }
           },"DD").start();
     }
}
  • 8锁
package com.javase.thread;
 
class TestSynchronized {
 
     public static synchronized void getIOS() throws InterruptedException {
           Thread.sleep(300);
           System.out.println("IOS");
     }
 
     public synchronized void getAndroid() {
           System.out.println("Android");
     }
 
     public void getHello() {
           System.out.println("Hello");
     }
}
 
/**
 * 测试8锁ytt5t66yhr
 *1  标准普通调用,先打印苹果还是android  ==>IOS
 *2  新添加Thread.sleep(4000),先打印苹果还是android  ==>IOS
 *3  新增加Hello方法,先打印苹果还是hello ==>hello
 *4 有两部手机,先打印苹果还是android ==>android
 *5 两个静态同步方法,同一部手机,先打印苹果还是android   ==>IOS
 *6 两个静态同步方法,有两部手机,先打印苹果还是android   ==>IOS
 *7 一个静态同步方法,一个普通同步方法,同一部手机,先打印苹果还是android   ==>android
 *8 一个静态同步方法,一个普通同步方法,有两部手机,先打印苹果还是android   ==>android
 * @author Bo
 *
 */
public class ThreadDemo3 {
 
     public static void main(String[] args) {
           final TestSynchronized tel = new TestSynchronized();
           final TestSynchronized tel2 = new TestSynchronized();
 
           new Thread(new Runnable() {
                public void run() {
                     try {
                           tel.getIOS();
                     } catch (InterruptedException e) {
                           e.printStackTrace();
                     }
                }
           }).start();
           new Thread(new Runnable() {
                public void run() {
                     tel2.getAndroid();
                }
           }).start();
//         new Thread(new Runnable() {
//              public void run() {
//                   tel.getHello();
//              }
//         }).start();
     }
}
线程锁笔记
 
  • 一个对象里面如果有多个synchronized方法,某一个时刻内,只要一个线程去调用其中的一个synchronized方法了,其它的线程都只能等待,换句话说,某一个时刻内,只能有唯一一个线程去访问这些synchronized方法
  • 锁的是当前对象this,被锁定后,其它的线程都不能进入到当前对象的其它的synchronized方法
  • 加个普通方法后发现和同步锁无关
  • 换成两个对象后,不是同一把锁了,情况立刻变化。
  • 都换成静态同步方法后,情况又变化
  • 所有的非静态同步方法用的都是同一把锁——实例对象本身,也就是说如果一个实例对象的非静态同步方法获取锁后,该实例对象的其他非静态同步方法必须等待获取锁的方法释放锁后才能获取锁,可是别的实例对象的非静态同步方法因为跟该实例对象的非静态同步方法用的是不同的锁,所以毋须等待该实例对象已获取锁的非静态同步方法释放锁就可以获取他们自己的锁。
  • 所有的静态同步方法用的也是同一把锁——类对象本身,这两把锁是两个不同的对象,所以静态同步方法与非静态同步方法之间是不会有竞态条件的。但是一旦一个静态同步方法获取锁后,其他的静态同步方法都必须等待该方法释放锁后才能获取锁,而不管是同一个实例对象的静态同步方法之间,还是不同的实例对象的静态同步方法之间,只要它们同一个类的实例对象!
 
 
  • 备注:多线程之间按顺序调用,实现A->B->C 三个线程启动,要求如下:
          AA打印5次,BB打印10次,CC打印15次 接着 AA打印5次,BB打印10次,CC打印15次
          共计来20轮
 
package com.javase.thread;
 
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
 
class MyResource {
     private int number = 1;
     private Lock lock = new ReentrantLock();
     private Condition condition1 = lock.newCondition();
     private Condition condition2 = lock.newCondition();
     private Condition condition3 = lock.newCondition();
 
     public void loopA(int loop_id) {
           lock.lock();
 
           try {
                while(number != 1) {
                     condition1.await();
                }
                for (int i = 0; i < 5; i++) {
                     System.out.println(Thread.currentThread().getName() +"\t"+ i + " : " + loop_id);
                }
                //标记+唤醒
                number = 2;
                condition2.signal();
           } catch (Exception e) {
                e.printStackTrace();
           } finally {
                lock.unlock();
           }
     }
 
     public void loopB(int loop_id) {
           lock.lock();
 
           try {
                while(number != 2) {
                     condition2.await();
                }
                for (int i = 0; i < 10; i++) {
                     System.out.println(Thread.currentThread().getName()  +"\t"+ i + " : " + loop_id);
                }
                //标记+唤醒
                number = 3;
                condition3.signal();
           } catch (Exception e) {
                e.printStackTrace();
           } finally {
                lock.unlock();
           }
     }
 
     public void loopC(int loop_id) {
           lock.lock();
 
           try {
                while(number != 3) {
                     condition3.await();
                }
                for (int i = 0; i < 15; i++) {
                     System.out.println(Thread.currentThread().getName() +"\t"+ i + " : " + loop_id);
                }
                System.out.println();
                //标记+唤醒
                number = 1;
                condition1.signal();
           } catch (Exception e) {
                e.printStackTrace();
           } finally {
                lock.unlock();
           }
     }
 
}
 
/**
 *
 * @author Bo 备注:多线程之间按顺序调用,实现A->B->C 三个线程启动,要求如下:
 *
 *         AA打印5次,BB打印10次,CC打印15次 接着 AA打印5次,BB打印10次,CC打印15次
 *
 *         共计来20轮
 */
public class ThreadDemo4 {
 
     public static void main(String[] args) {
 
           final MyResource myResource = new MyResource();
 
           new Thread(new Runnable() {
                public void run() {
                     for (int i = 0; i < 20; i++) {
                           myResource.loopA(i+1);
 
                     }
                }
           },"AA").start();
           new Thread(new Runnable() {
                public void run() {
                     for (int i = 0; i < 20; i++) {
                           myResource.loopB(i+1);
 
                     }
                }
           },"BB").start();
           new Thread(new Runnable() {
                public void run() {
                     for (int i = 0; i < 20; i++) {
                           myResource.loopC(i+1);
 
                     }
                }
           },"CC").start();
     }
}
  • 读写锁一个线程写,100个线程读取
package com.javase.thread;
 
import java.util.concurrent.locks.ReentrantReadWriteLock;
 
class Resource_RWLock {
     private int number = 1;
     private ReentrantReadWriteLock rwlock = new ReentrantReadWriteLock();
     private Object obj;
 
     public void set(Object obj) {
 
           rwlock.writeLock().lock();
           try {
                this.obj = obj;
                System.out.println(Thread.currentThread().getName() + " : " + obj);
 
           } catch (Exception e) {
                e.printStackTrace();
           } finally {
                rwlock.writeLock().unlock();
           }
     }
     public void get() {
           rwlock.writeLock().lock();
           try {
                System.out.println(Thread.currentThread().getName() + " : " + obj);
 
           } catch (Exception e) {
                e.printStackTrace();
           } finally {
                rwlock.writeLock().unlock();
           }
     }
}
 
/**
 *读写锁
 *一个线程写,100个线程读取
 * @author Bo
 *
 */
public class ThreadDemo5 {
 
     public static void main(String[] args) {
 
           final Resource_RWLock rwlock = new Resource_RWLock();
 
           new Thread(new Runnable() {
                public void run() {
                     rwlock.set("上车上车");
                }
           },"AA").start();
           for (int i = 1; i <= 100; i++) {
                new Thread(new Runnable() {
                     public void run() {
                           rwlock.get();
                     }
                },"BB"+i).start();
           }
     }
}
  • 线程池
private static void threadPoolTest() {
           //         ExecutorService threadPool = Executors.newFixedThreadPool(5);//指定几个线程
           //         ScheduledExecutorService threadPool = Executors.newSingleThreadScheduledExecutor();//单个
                     ExecutorService threadPool = Executors.newCachedThreadPool();//创建一个可根据需要创建新线程的线程池
                     Future<Integer> result = null;
                     try {
                           for (int i = 0; i < 200; i++) {
 
                                result = threadPool.submit(new Callable<Integer>() {
 
                                     @Override
                                     public Integer call() throws Exception {
                                          System.out.print(Thread.currentThread().getName() + "\t");
                                           return new Random().nextInt(20);
                                     }
                                });
                                System.out.println(result.get());
                           }
 
                     } catch (Exception e) {
                           e.printStackTrace();
                     } finally {
                           threadPool.shutdown();
                     }
     }
 
public static void main(String[] args) {
           ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(5);//可以指定线程之间相隔时间
           //ScheduledExecutorService threadPool = Executors.newSingleThreadScheduledExecutor();
          
           ScheduledFuture<Integer> result = null;
           try {
                for (int i = 0; i < 20; i++) {
 
                     result = threadPool.schedule(new Callable<Integer>() {
 
                           @Override
                           public Integer call() throws Exception {
                                System.out.print(Thread.currentThread().getName() + "\t");
                                return (int) (Math.random() * 20);
                           }
                     }, 2, TimeUnit.SECONDS);
                     System.out.println(result.get());
                }
           } catch (Exception e) {
                e.printStackTrace();
           } finally {
                threadPool.shutdown();
           }
     }
 
 
  • 进程和线程的定义、区别与联系
一、进程

进程:指在系统中能独立运行并作为资源分配的基本单位,它是由一组机器指令、数据和堆栈等组成的,是一个能独立运行的活动实体。

注意,进程一般有三个状态:就绪状态、执行状态和等待状态【或称阻塞状态】;进程只能由父进程建立,系统中所有的进程形成一种进程树的层次体系;挂起命令可由进程自己和其他进程发出,但是解除挂起命令只能由其他进程发出。

进程控制块(PCB):PCB不但可以记录进程的属性信息,以便操作系统对进程进行控制和管理,而且PCB标志着进程的存在,操作系统根据系统中是否有该进程的进程控制块PCB而知道该进程存在与否。系统建立进程的同时就建立该进程的PCB,在撤销一个进程时,也就撤销其PCB,故进程的PCB对进程来说是它存在的具体的物理标志和体现。一般PCB包括以下三类信息:进程标识信息;处理器状态信息;进程控制信息。

由程序段、相关的数据段和PCB三部分构成了进程实体(又称进程印像),一般,我们把进程实体就简称为进程。

进程的特征:
1.动态性:进程的实质是程序的一次执行过程,进程是动态产生,动态消亡的。
2.并发性:任何进程都可以同其他进程一起并发执行。
3.独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位。
4.异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度向前推进。

二、线程

线程:线程是进程中的一个实体,作为系统调度和分派的基本单位。Linux下的线程看作轻量级进程。

线程的性质:
1.线程是进程内的一个相对独立的可执行的单元。若把进程称为任务的话,那么线程则是应用中的一个子任务的执行。
2.由于线程是被调度的基本单元,而进程不是调度单元。所以,每个进程在创建时,至少需要同时为该进程创建一个线程。即进程中至少要有一个或一个以上的线程,否则该进程无法被调度执行。
3.进程是被分给并拥有资源的基本单元。同一进程内的多个线程共享该进程的资源,但线程并不拥有资源,只是使用他们。
4.线程是操作系统中基本调度单元,因此线程中应包含有调度所需要的必要信息,且在生命周期中有状态的变化。
5.由于共享资源【包括数据和文件】,所以线程间需要通信和同步机制,且需要时线程可以创建其他线程,但线程间不存在父子关系。

多线程使用的情形:前台和后台工作情况;异步处理工作情况;需要加快执行速度情况;组织复杂工作的情况;同时有多个用户服务请求的情况等。
 
线程机制的优点:
多线程运行在同一个进程的相同的地址空间内,和采用多进程相比有以下优点:
1.创建和撤销线程的开销较之进程要少。创建线程时只需要建立线程控制表相应的表目,或有关队列,而创建进程时,要创建PCB表和初始化,进入有关进程队列,建立它的地址空间和所需资源等。
2.CPU在线程之间开关时的开销远比进程要少得多。因开关线程都在同一地址空间内,只需要修改线程控制表或队列,不涉及地址空间和其他工作。
3.线程机制也增加了通讯的有效性。进程间的通讯往往要求内核的参与,以提供通讯机制和保护机制,而线程间的通讯是在同一进程的地址空间内,共享主存和文件,无需内核参与。

三、进程和线程的区别

(1)调度:
        在传统的操作系统中,CPU调度和分派的基本单位是进程。而在引入线程的操作系统中,则把线程作为CPU调度和分派的基本单位,进程则作为资源拥有的基本单位,从而使传统进程的两个属性分开,线程编程轻装运行,这样可以显著地提高系统的并发性。同一进程中线程的切换不会引起进程切换,从而避免了昂贵的系统调用,但是在由一个进程中的线程切换到另一进程中的线程,依然会引起进程切换。
 
(2)并发性:
      在引入线程的操作系统中,不仅进程之间可以并发执行,而且在一个进程中的多个线程之间也可以并发执行,因而使操作系统具有更好的并发性,从而更有效地提高系统资源和系统的吞吐量。例如,在一个为引入线程的单CPU操作系统中,若仅设置一个文件服务进程,当它由于某种原因被封锁时,便没有其他的文件服务进程来提供服务。在引入线程的操作系统中,可以在一个文件服务进程设置多个服务线程。当第一个线程等待时,文件服务进程中的第二个线程可以继续运行;当第二个线程封锁时,第三个线程可以继续执行,从而显著地提高了文件服务的质量以及系统的吞吐量。

(3)拥有资源:
      不论是引入了线程的操作系统,还是传统的操作系统,进程都是拥有系统资源的一个独立单位,他可以拥有自己的资源。一般地说,线程自己不能拥有资源(也有一点必不可少的资源),但它可以访问其隶属进程的资源,亦即一个进程的代码段、数据段以及系统资源(如已打开的文件、I/O设备等),可供同一个进程的其他所有线程共享。

(4)独立性:
        在同一进程中的不同线程之间的独立性要比不同进程之间的独立性低得多。这是因为

为防止进程之间彼此干扰和破坏,每个进程都拥有一个独立的地址空间和其它资源,除了共享全局变量外,不允许其它进程的访问。但是同一进程中的不同线程往往是为了提高并发性以及进行相互之间的合作而创建的,它们共享进程的内存地址空间和资源,如每个线程都可以访问它们所属进程地址空间中的所有地址,如一个线程的堆栈可以被其它线程读、写,甚至完全清除。

(5)系统开销:

由于在创建或撤销进程时,系统都要为之分配或回收资源,如内存空间、I/O设备等。因此,操作系统为此所付出的开销将显著地大于在创建或撤消线程时的开销。类似的,在进程切换时,涉及到整个当前进程CPU环境的保存环境的设置以及新被调度运行的CPU环境的设置,而线程切换只需保存和设置少量的寄存器的内容,并不涉及存储器管理方面的操作,可见,进程切换的开销也远大于线程切换的开销。此外,由于同一进程中的多个线程具有相同的地址空间,致使他们之间的同步和通信的实现也变得比较容易。在有的系统中,现成的切换、同步、和通信都无需操作系统内核的干预。

(6)支持多处理机系统:

       在多处理机系统中,对于传统的进程,即单线程进程,不管有多少处理机,该进程只能运行在一个处理机上。但对于多线程进程,就可以将一个进程中的多个线程分配到多个处理机上,使它们并行执行,这无疑将加速进程的完成。因此,现代处理机OS都无一例外地引入了多线程。

JUC笔记的更多相关文章

  1. Java并发编程--基础进阶高级(完结)

    Java并发编程--基础进阶高级完整笔记. 这都不知道是第几次刷狂神的JUC并发编程了,从第一次的迷茫到现在比较清晰,算是个大进步了,之前JUC笔记不见了,重新做一套笔记. 参考链接:https:// ...

  2. JUC.Condition学习笔记[附详细源码解析]

    目录 Condition的概念 大体实现流程 I.初始化状态 II.await()操作 III.signal()操作 3个主要方法 Condition的数据结构 线程何时阻塞和释放 await()方法 ...

  3. JUC.Lock(锁机制)学习笔记[附详细源码解析]

    锁机制学习笔记 目录: CAS的意义 锁的一些基本原理 ReentrantLock的相关代码结构 两个重要的状态 I.AQS的state(int类型,32位) II.Node的waitStatus 获 ...

  4. 学习笔记 07 --- JUC集合

    学习笔记 07 --- JUC集合 在讲JUC集合之前我们先总结一下Java的集合框架,主要包含Collection集合和Map类.Collection集合又能够划分为LIst和Set. 1. Lis ...

  5. JUC并发编程学习笔记

    JUC并发编程学习笔记 狂神JUC并发编程 总的来说还可以,学到一些新知识,但很多是学过的了,深入的部分不多. 线程与进程 进程:一个程序,程序的集合,比如一个音乐播发器,QQ程序等.一个进程往往包含 ...

  6. 狂神说JUC学习笔记(二)

    狂神说JUC的原版笔记: 链接:https://pan.baidu.com/s/12zrGI4JyZhmkQh0cqEO4BA 提取码:d65c 我的笔记在狂神的笔记上增加了一些知识点或者做了些许补充 ...

  7. 狂神说JUC学习笔记(一)

    狂神说JUC的原版笔记: 链接:https://pan.baidu.com/s/12zrGI4JyZhmkQh0cqEO4BA 提取码:d65c 我的笔记在狂神的笔记上增加了一些知识点或者做了些许修改 ...

  8. JUC学习笔记(六)

    JUC学习笔记(一)https://www.cnblogs.com/lm66/p/15118407.html JUC学习笔记(二)https://www.cnblogs.com/lm66/p/1511 ...

  9. JUC学习笔记(五)

    JUC学习笔记(一)https://www.cnblogs.com/lm66/p/15118407.html JUC学习笔记(二)https://www.cnblogs.com/lm66/p/1511 ...

随机推荐

  1. day 21 - 1 包,异常处理

    创建目录代码 1. 无论是 import 形式还是 from...import 形式,凡是在导入语句中(而不是在使用时)遇到带点的,都要第一时间提高警觉:这是关于包才有的导入语法2. 包是目录级的(文 ...

  2. 2018-2019-2 20175306实验二面向对象程序设计《Java开发环境的熟悉》实验报告

    2018-2019-2 20175306实验二面向对象程序设计<Java开发环境的熟悉>实验报告 面向对象程序设计-1 实验要求: 参考:> http://www.cnblogs.c ...

  3. 没有显示器如何SSH连接上树莓派

    1.在用读卡器烧录系统后先用Linux虚拟机连接上读卡器,修改 sudo gedit /etc/wpa_supplicant/wpa_supplicant.conf 加入 network={ ssid ...

  4. 通过scrollTop,使子元素滚动至指定位置

    想实现这样的一个功能,点击子元素,让元素滚动至指定位置,怎么实现呢? 在代码实现之前,先了解下相关关键点. 1.scrollHeight 属性 通过 scrollHeight 属性可获得子元素的滚动高 ...

  5. Python爬虫从入门到进阶(4)之xpath的使用

    官网地址:https://lxml.de/xpathxslt.html 导入: from lxml import etree lxml.tree 支持 ElementTree 和 Element 上的 ...

  6. # 20175333曹雅坤《Java程序设计》第四周学习总结

    教材学习内容总结 第五章:子类与继承 5.1子类与父类:关键字extends 5.2子类的继承性:如果子类与父类在一个包中,除了private其他都可以继承:如果不在一个包中,则private和友好都 ...

  7. 机器学习基石12-Nonlinear Transformation

    注: 文章中所有的图片均来自台湾大学林轩田<机器学习基石>课程. 笔记原作者:红色石头 微信公众号:AI有道 上一节课介绍了分类问题的三种线性模型,可以用来解决binary classif ...

  8. 题解 P5301 【[GXOI/GZOI2019]宝牌一大堆】

    这道题除了非常恶心以外也没有什么非常让人恶心的地方 当然一定要说有的话还是有的,就是这题和咱 ZJOI 的 mahjong 真的是好像的说~ 于是就想说这道题出题人应该被 锕 掉 noteskey 整 ...

  9. crontab和at任务

    crontab周期任务 名称解释: cron来源于希腊语 chronos(χρόνος),原意是时间.(引用自维基百科) tab全称是table,表 常用参数: -e 编辑crontab文件 -l 显 ...

  10. Linux S和T权限

    S (setuid) 场景: 像修改密码的流程其实就是通过 /usr/bin/passwd 命令对 /etc/passwd进行修改,我们需要修改自己的密码(就是修改/etc/shadow),然而普通用 ...