package com.ricky.parameterized;
import java.util.ArrayList;
public class ListSample {
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add("hello");
list.add("haha");
list.add(12345);
String str = (String)list.get(1);
System.out.println(str.substring(0, 2));
}
}
不使用泛型同样可以插入元素,但编译器不会对元素的类型进行检查,取出元素时返回的都是Object对象
package com.ricky.parameterized;
import java.util.ArrayList;
public class ListSample {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList();
list.add("hello");
list.add("haha");
// list.add(12345); // 报错
System.out.println(list.get(1).substring(0, 2));
}
}
自定义泛型类,需要在类名后增加"<标识符>":如:public class SampleClass
package com.ricky.parameterized;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class CollectionUtils<E> {
private List<E> data = new ArrayList();
public void add(E element) {
data.add(element);
}
public E randomSelect() {
Random random = new Random();
return data.get(random.nextInt(data.size()));
}
public static void main(String[] args) {
CollectionUtils<String> utils = new CollectionUtils<>();
utils.add("haha");
utils.add("xixi");
utils.add("heihei");
utils.add("huhu");
System.out.println(utils.randomSelect());
}
}
JDK 1.5以后还提供了泛型方法的支持,允许在类没有声明泛型的前提下让方法独立使用泛型进行开发
package com.ricky.parameterized;
import java.util.ArrayList;
import java.util.List;
public class PtMethod {
public <T> List<T> transferToList(T[] array) {
List<T> list = new ArrayList<>();
for (T item : array) {
list.add(item);
}
return list;
}
public static void main(String[] args) {
PtMethod ptMethod = new PtMethod();
String[] array = new String[]{"A", "B", "C", "D"};
List<String> list = ptMethod.transferToList(array);
System.out.println(list);
}
}
泛型的匹配规则
通过extends与super限定范围
extends关键字代表必须传入Shape或者子类才通过检查
public void doSth(List<? extends Shape> shapeList)
super关键字代表必须传入Rectangle或者其父类才能通过检查
public void doSth(List<? super Rectangle> shapeList)
程序是静态文件,进程是程序运行后在内存中的实例
线程是进程内执行的“任务”
Java中进程与线程

package com.ricky.thread;
import java.util.Random;
public class ThreadSample {
class Runner extends Thread {
@Override
public void run() {
Integer speed = new Random().nextInt(10);
for (int i = 1; i <= 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("第" + i + "秒:" + this.getName() + "已跑到" + (i * speed) + "米(" + speed + "米/秒)");
}
}
}
public void start() {
Runner threadA = new Runner();
threadA.setName("A");
Runner threadB = new Runner();
threadB.setName("B");
Runner threadC = new Runner();
threadC.setName("C");
Runner threadD = new Runner();
threadD.setName("D");
threadA.start();
threadB.start();
threadC.start();
threadD.start();
}
public static void main(String[] args) {
ThreadSample threadSample = new ThreadSample();
threadSample.start();
}
}
此方法不太推荐,因为Java是单继承的,继承了Thread类就无法再继承其它的类了,因而我们更偏向于使用接口
更为推荐的方式
package com.ricky.thread;
import java.util.Random;
public class ThreadSample {
class Runner implements Runnable {
@Override
public void run() {
Integer speed = new Random().nextInt(9) + 1;
for (int i = 1; i <= 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("第" + i + "秒:" + Thread.currentThread().getName() + "已跑到" + (i * speed) + "米(" + speed + "米/秒)");
}
}
}
public void start() {
Runner runner = new Runner();
Thread threadA = new Thread(runner);
threadA.setName("A");
threadA.start();
Thread threadB = new Thread(runner);
threadB.setName("B");
threadB.start();
Thread threadC = new Thread(runner);
threadC.setName("C");
threadC.start();
Thread threadD = new Thread(runner);
threadD.setName("D");
threadD.start();
}
public static void main(String[] args) {
ThreadSample threadSample = new ThreadSample();
threadSample.start();
}
}
允许线程执行后将值进行返回,这是Callable接口的特点
package com.ricky.thread;
import java.util.Random;
import java.util.concurrent.*;
public class ThreadSample {
class Runner implements Callable<Integer> { // 有泛型是因为使用Callable接口支持返回值
public String name;
@Override
public Integer call() {
Integer speed = new Random().nextInt(9) + 1;
Integer totalMeter = 0;
for (int i = 1; i <= 10; i++) {
Thread.sleep(1000);
totalMeter += speed;
System.out.println("第" + i + "秒:" + this.name + "已跑到" + (i * speed) + "米(" + speed + "米/秒)");
}
return totalMeter;
}
}
public void start() throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(4);
Runner threadA = new Runner();
threadA.name = "A";
Runner threadB = new Runner();
threadB.name = "B";
Runner threadC = new Runner();
threadC.name = "C";
Runner threadD = new Runner();
threadD.name = "D";
Future<Integer> r1 = executorService.submit(threadA);
Future<Integer> r2 = executorService.submit(threadB);
Future<Integer> r3 = executorService.submit(threadC);
Future<Integer> r4 = executorService.submit(threadD);
executorService.shutdown();
System.out.println(threadA.name + "累计跑了" + r1.get() + "米");
System.out.println(threadB.name + "累计跑了" + r2.get() + "米");
System.out.println(threadC.name + "累计跑了" + r3.get() + "米");
System.out.println(threadD.name + "累计跑了" + r4.get() + "米");
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
ThreadSample threadSample = new ThreadSample();
threadSample.start();
}
}
代码中的同步机制:synchronized(同步锁)关键字的作用就是利用一个特定的对象设置一个锁lock,在多线程并发访问的时候,同时只允许一个线程可以获得这个锁,执行特定的代码,执行后释放锁,继续由其他线程争抢
package com.ricky.thread;
public class SyncSample {
class Printer {
Object lock = new Object(); // 锁对象
public void print() {
synchronized (lock) {
try {
Thread.sleep(500);
System.out.print("魑");
Thread.sleep(500);
System.out.print("魅");
Thread.sleep(500);
System.out.print("魍");
Thread.sleep(500);
System.out.print("魉");
System.out.println();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class PrintTask implements Runnable {
public Printer printer;
@Override
public void run() {
printer.print();
}
}
public void start() {
Printer printer = new Printer(); // 让十个线程拥有同一个锁对象,这样才能达到效果
for (int i = 0; i < 10; i++) {
PrintTask task = new PrintTask();
task.printer = printer;
Thread thread = new Thread(task);
thread.start();
}
}
public static void main(String[] args) {
SyncSample syncSample = new SyncSample();
syncSample.start();
}
}
最常用
package com.ricky.thread;
public class SyncSample {
class Printer {
public synchronized void print() { // 不需要指名锁对象,默认使用this关键字作为锁对象
try {
Thread.sleep(500);
System.out.print("魑");
Thread.sleep(500);
System.out.print("魅");
Thread.sleep(500);
System.out.print("魍");
Thread.sleep(500);
System.out.print("魉");
System.out.println();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class PrintTask implements Runnable {
public Printer printer;
@Override
public void run() {
printer.print();
}
}
public void start() {
Printer printer = new Printer();
for (int i = 0; i < 10; i++) {
PrintTask task = new PrintTask();
task.printer = printer;
Thread thread = new Thread(task);
thread.start();
}
}
public static void main(String[] args) {
SyncSample syncSample = new SyncSample();
syncSample.start();
}
}
静态方法同样也是直接在static后加上synchronized关键字即可,但要注意这里的锁对象不再是this,静态方法没有this,默认使用类名.class字节码对象来加锁
在拥有共享数据的多条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且正确的执行,不会出现数据污染等意外情况
“超卖”现象
进行库存判断的时候其余线程仍未进行库存递减

这时候就需要给售卖这个函数加锁,让每个线程一个一个有序的执行
并发是伴随着多核处理器的诞生而产生的,为了充分利用硬件资源,诞生了多线程技术。但是多线程又存在资源竞争的问题,引发了同步和互斥的问题,JDK 1.5推出的java.util.concurrent(并发工具包)来解决这些问题
Runnable接口的弊端
ThreadPool线程池
JUC支持的线程池种类
在java.util.concurrent中,提供了工具类Executors(调度器)对象来创建线程池,可创建的线程池有四种:
package com.ricky.thread;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ThreadPool {
public static void main(String[] args) {
// 创建一个定长的线程池
// 定长线程池的特点是固定线程总数,空闲线程用于执行任务,如果线程都在使用,后续任务则处在等待状态
ExecutorService threadPool = Executors.newFixedThreadPool(10);
for (int i = 1; i <= 1000; i++) {
final int index = i;
// 不需要返回值,使用execute方法执行Runnable对象
threadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ":" + index);
}
});
/*
// 需要返回值,使用submit方法执行Callable对象,利用Future对象接收返回值
Future
}
threadPool.shutdown();
}
}
package com.ricky.thread;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPool {
public static void main(String[] args) {
// 调度器对象
// ExecutorService用于管理线程池
ExecutorService threadPool = Executors.newCachedThreadPool(); // 创建一个可缓存线程池
// 了缓存线程池的特点是:无限大,如果线程池中没有可用的线程则创建,有空闲线程则利用起来
for (int i = 1; i <= 1000; i++) {
final int index = i;
// 不需要返回值,使用execute方法执行Runnable对象
threadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ":" + index);
}
});
}
threadPool.shutdown();
}
}
用的比较少
package com.ricky.thread;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPool {
public static void main(String[] args) {
// 调度器对象
// ExecutorService用于管理线程池
ExecutorService threadPool = Executors.newSingleThreadExecutor(); // 单线程线程池
for (int i = 1; i <= 1000; i++) {
final int index = i;
// 不需要返回值,使用execute方法执行Runnable对象
threadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ":" + index);
}
});
}
threadPool.shutdown();
}
}
package com.ricky.thread;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPool {
public static void main(String[] args) {
// 调度线程池
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
// 延迟1秒执行,每3秒执行一次
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println(new Date() + " 延迟1秒执行,每三秒执行一次");
}
}, 1, 3, TimeUnit.SECONDS);
}
}